Crashed: com.apple.root.default-qos - ios

I have a fairly simple app that parses a RSS feed and shows it's content in a table view. It's available on the App Store. I have Crashlytics crash reporting integrated. I recently received two reports. These are a little difficult to decipher.
This has occurred in an iPhone 6 running iOS 10.2.1.
This is from an iPhone 5 running iOS 10.2.1.
Even though it says it's crashing due to privacy violations, I'm not accessing any services that requires permission in my app.
Also searching on com.apple.root.default-qos lead me to believe that this may have something to do with background threads. The only place where I use a background thread is to parse the RSS feed data.
DispatchQueue.global(qos: .background).async {
guard let data = try? Data(contentsOf: URL) else {
return
}
do {
let xmlDoc = try AEXMLDocument(xml: data)
if let items = xmlDoc.root["channel"]["item"].all {
self.posts.removeAll()
for item in items {
let title = item["title"].value ?? ""
// ...
self.posts.append(jobPost)
}
DispatchQueue.main.async {
self.saveposts(self.posts)
self.posts.sort { $0.publishDate > $1.publishDate }
self.tableView.reloadData()
UIApplication.shared.toggleNetworkActivityIndicator(show: false)
self.toggleUI(enable: true)
if self.refreshControl.isRefreshing { self.refreshControl.endRefreshing() }
}
}
} catch let error as NSError {
print("RSS parsing failed: \(error)")
self.showErrorAlert(error)
UIApplication.shared.toggleNetworkActivityIndicator(show: false)
self.toggleUI(enable: true)
if self.refreshControl.isRefreshing { self.refreshControl.endRefreshing() }
}
}
I tested this code on my iPhone 5 running iOS 9.3.5 and simulators running iOS 10.2 but no crash occurred.
Is there any other way to track down this problem?

I would double check all your permissions. In my case, starting with iOS10 you need permissions to save stuff to the user's camera roll. In my app, I was showing a default share sheet and whenever a user selected "save photo" the app crashed with one of these very not helpful error messages. I added
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Allow you to save charts and graphs from the app to your phone.</string>
to my info.plist, clean & run. And everything the problem was solved.

Related

Unable to bypass error code 4 when using HealthKit through the simulator

I'm creating a new multiplatform app using the Xcode beta run on macOS Ventura beta. I want to use HealthKit to submit mindfulness minutes but I can't get it working. I created a new app with JUST this and I have the same issue so I came here hoping someone knows how to fix it.
The ContentView for the app is:
import SwiftUI
import HealthKit
struct ContentView: View {
// You need only a single HealthKit store per app. These are long-lived objects; you create the store once, and keep a reference for later use.
let myHealthStore = HKHealthStore()
let typestoRead = Set([HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.mindfulSession)!])
let mindfulType = HKObjectType.categoryType(forIdentifier: .mindfulSession)
#State var message: String?
var body: some View {
NavigationView {
if HKHealthStore.isHealthDataAvailable() {
Text("Health Data Available")
} else {
Text("Health Data NOT Available")
}
Button(action: {
print("Setting 1 minute Mindfulness")
let startTime = Date()
let endTime = startTime.addingTimeInterval(2.0 * 60.0)
print("From \(startTime) until \(endTime).")
// Create a mindful session with the given start and end time
let mindfullSample = HKCategorySample(type:mindfulType!, value: 0, start: startTime, end: endTime)
// Save it to the health store
myHealthStore.save(mindfullSample, withCompletion: { (success, error) -> Void in
print("in completion")
if error != nil {
print("error: \(error!)")
message = "Failure: \(error!)"
return
}
print("New data was saved in HealthKit: \(success)")
message = "Success: \(success)"
})
}, label: {
Text("Set 1 Minute Mindfulness")
})
.buttonStyle(.bordered)
Divider()
Text(message ?? "No Message.... yet")
}
.onAppear() {
print("ContentView appears")
myHealthStore.requestAuthorization(toShare: [], read: typestoRead) { (success, error) -> Void in
if(success){
// Read or write the HealthKit data
print("success: \(success)")
}
else{
// Authorization failure
print("error: \(error!)")
}
}
}
}
}
Additionally I went to Application, Target, Info, and pressed the plus sign to add the following PLIST values:
Privacy - Health Records Usage Description
Privacy - Health Update Usage Description
Privacy - Health Share Usage Description
I also went to Application > Target > Signing & Capabilities > and pressed the plus to add HealthKit and check off Background Delivery.
This got me past the first error but now when I run it I either get an error code 1 or 4. One is understandable, when run on my iPad or Mac as apparently Health data is unavailable on this device but, when run on the iOS simulator I don't understand how to get past the error:
Error Domain=com.apple.healthkit Code=4 "Missing application-identifier entitlement" UserInfo={NSLocalizedDescription=Missing application-identifier entitlement}
What am I missing? I looked online but most people with this error seem to be updating an app. This is a newly created app. Just in case I've uninstalled it and reinstalled it on the simulator, chose a different simulator, and created a new bare bones app. Any tips to access HealthKit?
Please confirm that there is a bundle id string listed in the entitlements plist for the application-identifier key? Error Code 4 is referring to that missing.

WKInterfaceMap blank rendering

WKInterfaceMap sometimes renders blank in a very simple app I am developing. The map appears completely empty (no grid of lines or anything similar). It looks as though the thread responsible for drawing the tiles gets blocked.
In order to reproduce the issue just add the code below to the extension delegate.
func applicationDidEnterBackground() {
let watchExtension = WKExtension.shared()
// Schedule the background refresh task.
watchExtension.scheduleBackgroundRefresh(withPreferredDate: Date().addingTimeInterval(15.0*60.0), userInfo: nil) { (error) in
// Check for errors.
if let error = error {
print("ExtensionDelegate: \(error.localizedDescription)")
return
}
print("ExtensionDelegate: Background Task scheduled successfuly")
}
}
Add a WKInterfaceMap to the main view and run once on the simulator. Close the app using the crown and stop it from XCode. Wait for at least 15 minutes and open the app again directly from the simulator.
The map renders then as in the image below.

Saving then accessing entity from managedObjectContext in CoreData occasionally crashes

I'm struggling to debug a hard-to-reproduce-locally crash in my app. The crash reports show the exception type is EXC_BAD_ACCESS (SIGSEGV) with objc_msgSend at the top of the crashed thread, perhaps suggesting "The process may have attempted to message a deallocated object" (as per Apple's documents).
I have not been able to recreate the crash or find any zombies using the Zombies instrument, despite using an older device and the same simulated device causing the most crashes.
From the trace I'm pretty sure I've been able to work out where the crash is occurring, but I'm not sure what I'm doing wrong.
My app is basically a group database. The app takes a username and password, sending them to a server to check if the person can be logged in. If valid, the app downloads the data on all the people in the group, then finds the logged in person from the downloaded data based on their username.
Because of the way the server code is set up, the username must be present in the downloaded data (if it all downloads correctly), yet my code occasionally fails to find them, and (from the crash logs) also occasionally this attempted finding of the person causes a crash.
coreDataStack.storeContainer.performBackgroundTask() { context in
OverallNetworkCalls.deleteAllLoadPeople(moContext: context) { result in
self.coreDataStack.saveNewContext(context: context)
if result == .success {
let person = AdministrativeHelperFunctions.returnCurrentUserFromUserName(moContext: context)
if let person = person {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
}
UserDefaults.standard.set(person.objectID.uriRepresentation(), forKey: udl.CurrentUserMOID.rawValue)
} else {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.loadingLabel.text = "Data was downloaded but your username isn't there. Try deleting and reloading the app, or contact admin."
}
}
}
func saveNewContext(context: NSManagedObjectContext) {
context.perform {
guard context.hasChanges else { return }
do {
try context.save()
} catch {
//logs the issue locally
}
}
}
func returnCurrentUserFromUserName(moContext: NSManagedObjectContext) -> Person? {
let userName = UserDefaults.standard.string(forKey: "username")
if let userName = userName {
//Create predicate, arrayForResults etc
do {
userNameMatchesArray = try moContext.fetch(fetchRequest)
} catch {
//logs the issue locally
}
if userNameMatchesArray.count == 1 {
return userNameMatchesArray[0]
} else {
return nil
}
} else {
return nil
}
}
My suspicion is that the returnCurrentUserFromUserName function is returning the user before the saveNewContext function has completed its task and that this is contributing to the issue, though given the same managedObjectContext is saving then retrieving the person I had originally assumed this wasn't a problem. I'm also not sure that using "context.perform" in the saveNewContext function is necessary/wise/useful; I'd value feedback on this too if anyone knows best practice inside a performBackgroundTask block.
A non-reproduceable bug is always the most frustrating to fix, and because of this anything I try to fix it won't be shown until I send it to my beta testers and get crashlogs back (or not!).
Thanks in advance for reviewing this problem.

Force user to update the app programmatically in iOS

In my iOS app I have enabled force app update feature. It is like this.
If there is a critical bug fix. In the server we are setting the new release version. And in splash screen I am checking the current app version and if its lower than the service version, shows a message to update the app.
I have put 2 buttons "Update now", "Update later"
I have 2 questions
If I click now. App should open my app in the appstore with the button UPDATE. Currently I use the link "http://appstore.com/mycompanynamepvtltd"
This opens list of my company apps but it has the button OPEN, not the UPDATE even there is a new update for my app. whats the url to go for update page?
If he click the button "Update Later" is it ok to close the app programmatically? Does this cause to reject my app in the appstore?
Please help me for these 2 questions
Point 2 : You should only allow force update as an option if you don't want user to update later. Closing the app programmatically is not the right option.
Point 1 : You can use a good library available for this purpose.
Usage in Swift:
Library
func applicationDidBecomeActive(application: UIApplication) {
/* Perform daily (.daily) or weekly (.weekly) checks for new version of your app.
Useful if user returns to your app from the background after extended period of time.
Place in applicationDidBecomeActive(_:)*/
Siren.shared.checkVersion(checkType: .daily)
}
Usage in Objective-C: Library
-(void)applicationDidBecomeActive:(UIApplication *)application {
// Perform daily check for new version of your app
[[Harpy sharedInstance] checkVersionDaily];
}
How it works : It used lookup api which returns app details like link including version and compares it.
For an example, look up Yelp Software application by iTunes ID by calling https://itunes.apple.com/lookup?id=284910350
For more info, please visit link
Don't close the app programmatically. Apple can reject the app. Better approach will be do not allow user to use the app. Keep the update button. Either user will go to app store or close the app by himself.
According to Apple, your app should not terminate on its own. Since the user did not hit the Home button, any return to the Home screen gives the user the impression that your app crashed. This is confusing, non-standard behavior and should be avoided.
Please check this forum:
https://forums.developer.apple.com/thread/52767.
It is happening with lot of people. In my project I redirected the user to our website page of downloading app from app store. In that way if the user is not getting update button in app store, at least the user can use the website in safari for the time being.
To specifically answer your question:
Use this URL to directly open to your app in the app store:
https://apps.apple.com/app/id########## where ########## is your app's 10 digit numeric ID. You can find that ID in App Store Connect under the App Information section. It's called "Apple ID".
I actually have terminate functionality built into my app if it becomes so out of date that it can no longer act on the data it receives from the server (my app is an information app that requires connectivity to my web service). My app has not been rejected for having this functionality after a dozen updates over a couple years, although that function has never been invoked. I will be switching to a static message instead of terminating the app, just to be safe to avoid future updates from being rejected.
I have found that the review process is at least somewhat subjective, and different reviewers may focus on different things and reject over something that has previously been overlooked many times.
func appUpdateAvailable() -> (Bool,String?) {
guard let info = Bundle.main.infoDictionary,
let identifier = info["CFBundleIdentifier"] as? String else {
return (false,nil)
}
// let storeInfoURL: String = "http://itunes.apple.com/lookupbundleId=\(identifier)&country=IN"
let storeInfoURL:String = "https://itunes.apple.com/IN/lookup?
bundleId=\(identifier)"
var upgradeAvailable = false
var versionAvailable = ""
// Get the main bundle of the app so that we can determine the app's
version number
let bundle = Bundle.main
if let infoDictionary = bundle.infoDictionary {
// The URL for this app on the iTunes store uses the Apple ID
for the This never changes, so it is a constant
let urlOnAppStore = NSURL(string: storeInfoURL)
if let dataInJSON = NSData(contentsOf: urlOnAppStore! as URL) {
// Try to deserialize the JSON that we got
if let dict: NSDictionary = try?
JSONSerialization.jsonObject(with: dataInJSON as Data, options:
JSONSerialization.ReadingOptions.allowFragments) as! [String:
AnyObject] as NSDictionary? {
if let results:NSArray = dict["results"] as? NSArray {
if let version = (results[0] as! [String:Any]).
["version"] as? String {
// Get the version number of the current version
installed on device
if let currentVersion =
infoDictionary["CFBundleShortVersionString"] as? String {
// Check if they are the same. If not, an
upgrade is available.
print("\(version)")
if version != currentVersion {
upgradeAvailable = true
versionAvailable = version
}
}
}
}
}
}
}
return (upgradeAvailable,versionAvailable)
}
func checkAppVersion(controller: UIViewController){
let appVersion = ForceUpdateAppVersion.shared.appUpdateAvailable()
if appVersion.0 {
alertController(controller: controller, title: "New Update", message: "New version \(appVersion.1 ?? "") is available")
}
}
func alertController(controller:UIViewController,title: String,message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Update", style: .default, handler: { alert in
guard let url = URL(string: "itms-apps://itunes.apple.com/app/ewap/id1536714073") else { return }
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}))
DispatchQueue.main.async {
controller.present(alertController, animated: true)
}
}
Use appgrades.io. Keep your app focus on delivering the business value and let 3rd party solution do their tricks. With appgrades, you can, once SDK integrated, create a custom view/alert to display for your old versions users asking them to update their apps. You can customize everything in the restriction view/alert to make it appear as part of your app.

Call blocking feature in iOS 10

I am trying to integrate CallDirectory Extension for blocking some incoming call. But application is not even recognising the numbers provided for blocking. Is there anyone who have succeeded in doing this ??
You can see the format that i have used..
private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ 18775555555, 18885555555,+91949520]
let labels = [ "Telemarketer", "Local business","myPhone"]
for (phoneNumber, label) in zip(phoneNumbers, labels) {
context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)
}
}
And , i referred this for development. http://iphoneramble.blogspot.in/2016/07/ios-10-callkit-directory-extension.html
Testing Device & iOS Version - iphone 5s ,iOS 10.1
Atlast , I have got the solution for call blocking. I haven't had a way to check if the call blocking code is working or not. Here are some of the things that i have done for making it work.
Check if your application is running in 64 bit iOS device
(iphone 5s or greater devices)
Adding the numbers in numerically ascending order
Add country code to every number
A sample code for adding mobile numbers for blocking is given below
let phoneNumber : CXCallDirectoryPhoneNumber =
CXCallDirectoryPhoneNumber("+9194******")!
context.addBlockingEntry(withNextSequentialPhoneNumber: phoneNumber)
Check your application has given permission to black calls
(setting -> phone -> call Blocking & identification -> Check your app is allowed to block calls)
You can also check the enabledStatus by putting this below code in your viewController
CXCallDirectoryManager.sharedInstance.getEnabledStatusForExtension(withIdentifier:
"bundleIdentifierOfYourExtension", completionHandler:
{(status, error) -> Void in
if let error = error {
print(error.localizedDescription)
}
})
Also , add following code to viewController
CXCallDirectoryManager.sharedInstance.reloadExtension(withIdentifier:
“bundleIdentifierOfYourExtension”, completionHandler: { (error) -> Void in
if let error = error {
print(error.localizedDescription)
}
})
You will find these url's helpful for the development.
http://iphoneramble.blogspot.in/2016/07/ios-10-callkit-directory-extension.html
https://translate.google.com/translate?hl=en&sl=zh-CN&u=http://colin1994.github.io/2016/06/17/Call-Directory-Extension-Study/&prev=search
Kindly please let me know if you have got improved methods and corrections.
Thanks and happy coding.
Good to see Apple listening to enhancement requests with CX. With iOS 13.4, Apple added the ability to open Call Blocking & Identification settings directly from the app.
func openSettings(completionHandler completion: ((Error?) -> Void)? = nil)
https://developer.apple.com/documentation/callkit/cxcalldirectorymanager/3521394-opensettings
The array of phone numbers must be a sorted list of int64's. From smallest to largest. The list will be rejected with an "entries out of order" error otherwise.

Resources