I want to disable this crash popup emitted from the crashlytics framework, but still send the crash.
I've seen in the doc that you can filter the dispatch using "CrashlyticsDelegate" but I can't figure out how to shut down this. (also the doc last update is Last updated: 2017-01-20, am I missing something here o.O)
Also using strings I see some methods such as:
alertWithTitle:message:delegate:cancelButtonTitle:otherButtonTitle:
setupAndDisplayAlertWithTitle:message:cancel:send:alwaysSend:report:
So the questions:
Is it at least possible to disable it?
If it is, how?
I wonder if it comes from an older version of crashlytics, explaining maybe why I'm not able to find it in the doc~
EDIT: I tested the delegate's methods provided to intercept the crash before sending it
Using - (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report; the doc says (in the header since the internet doc isn't up to date):
it is not called synchronously during initialization
it does not give you the ability to prevent the report from being submitted
the report object itself is immutable
So this one doesn't provide any way of removing the popup.
Using - (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler; the doc says (in header again):
Invoking completionHandler with NO will cause the detected report to be deleted and not submitted to Crashlytics. This is useful for implementing permission prompts, or other more-complex forms of logic around submitting crashes.
Can't disable the popup here either.
Moreover I don't see what is the point of having a "permission prompt" like they say if you can't remove theirs :(
You can disable the privacy dialog pop-up in the app settings page
https://docs.fabric.io/android/crashlytics/advanced-setup.html#use-the-privacy-dialog
Here is a screenshot of where it hides:
Related
I tested:
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
which is for putting app on background and it works.
How do I put app back on foreground?
I tried:
UIControl().sendAction(#selector(URLSessionTask.resume), to: UIApplication.shared, for: nil)
But eventually it crashes...
Thank you
Update:
Since you've indicated that you're looking for any technical solution, even those not compatible with the App Store or Apple's terms, this should be possible using the Private API LSApplicationWorkspace: openApplicationWithBundleID. Try something like this:
Create a .h file and set up an interface to the LSApplicationWorkspace class and list the required method. You will need to #import "PrivateHeaders.h" in your bridging header.
//
// PrivateHeaders.h
//
#ifndef PrivateHeaders_h
#define PrivateHeaders_h
#interface LSApplicationWorkspace : NSObject
- (bool)openApplicationWithBundleID:(id)arg1;
#end
#endif /* PrivateHeaders_h */
You should then be able to call this function and pass in the Bundle Identifier of your app as an string.
//
// SomeClass.swift
//
import MobileCoreServices
let workspace = LSApplicationWorkspace()
/**
Launch an App given its bundle identifier
- parameter bundleIdentifier: The bundle identifier of the app to launch
- returns: True if app is launched, otherwise false
*/
func openApp(withBundleIdentifier bundleIdentifier: String) -> Bool {
// Call the Private API LSApplicationWorkspace method
return workspace.openApplication(withBundleID: bundleIdentifier)
}
Original:
What you are doing is likely a violation of the iOS Human Interface Guidelines (although the "Don’t Quit Programmatically" is no longer specifically defined), so as the comments have said, it is not suited to the App Store. Regardless, once your app is suspended in this way, I don't expect that there is a way to resume it programmatically, unless you can hook into a Background Operation to run URLSessionTask.resume, but I have not tested it and am unsure whether it can work.
Apps can be launched (and hence brought into the foreground) programmatically from another app or today extension by using a Custom URL Scheme, or via a Push Notification. It isn't possible to launch the app from the Background Operation via a URL Scheme, since it is part of the UIKit framework, which must be run in the main thread.
In summary, I think your best option is to try to use a Notification. This just means that the user will need to click on the notification to bring your app back into the foreground.
Closing/opening the app should be done explicitly by the user. Any other way of closing or opening the app is not supported by Apple and will be rejected when uploaded to app store. iOS Human Interface Guideline states:
Don’t Quit Programmatically
Never quit an iOS application
programmatically because people tend to interpret this as a crash.
However, if external circumstances prevent your application from
functioning as intended, you need to tell your users about the
situation and explain what they can do about it. Depending on how
severe the application malfunction is, you have two choices.
*Display
an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures usersthat
there’s nothing wrong with your application. It puts usersin control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
*If only some of your application's features are
not working, display either a screen or an alert when people activate
the feature. Display the alert only when people try to accessthe
feature that isn’t functioning
Just as a follow up to Jordan's excellent answer I want to give an explanation for why your code works in the first place and why that alone will get your app rejected, even without any functionality to make it active again and bring it to the foreground.
As maddy pointed out in a comment, you're basically calling a method from UIApplication's private API. This works due to the Objective-C runtime's dynamic linking. You might wonder "But I am using Swift, what does that have to do with Objective-C?" The answer lies in #selector mechanism. A Selector is basically just a symbol that the Objective-C runtime looks up in a table to get a method it invokes (for you). This is why it's technically not correct to say you "call a method" when you do something like myObjectInstance.someMethod(). The correct way to phrase that would be to "send a message" to the object, because that's what is happening in the runtime. The target-action mechanism is build around that. The sendAction(_: Selector?, to: Any?) method does the same thing. So in effect your code does the following:
Get the symbol that corresponds to URLSessionTask's suspend() method.
Tell the shared instance of UIApplication to invoke the method that it has for that symbol.
Now usually that would result in a crash with the typical "unknown selector sent to instance..." error message. But here, by sure coincidence UIApplication also has a method for that instance (or rather, the runtime also has one of its methods listed in its table for that symbol). You kind of "found" a method that is not declared in its public header. You successfully circumvented a compile-time check for this and invoke a method that is part of a private API. This is explicitly forbidden in the Apple Developer Program License Agreement
Besides all that, I would strongly advise against trying to design an app that way in the first place. As maddy pointed out it's also likely considered to violate the HIGs. Even if you're not trying to do anything malicious and properly explain the feature in your app's description, that won't make Apple let it slide (I assume). Personally, as a user, I'd also find it annoying if the app did something the system already has a specific mechanic for in a different manner, at least in terms of app's coming to background and foreground.
I don't think it can be done without user interaction
The option is you can generate a push notification to tell the user to bring the application to foreground
When the operating system delivers push notification and the target application is not running in the foreground, it presents the notification.
If there is a notification alert and the user taps or clicks the action button (or moves the action slider), the application launches and calls a method to pass in the local-notification object or remote-notification payload.
I'm developing an iOS app using MFP 7.0.
Each screen (i.e., view controller) has a unique ID, and I am supposed to use Operational Analytics to send the following info to the server:
How long the user spent on each screen
On which screen the app crashed
Regarding #1, I guess I am supposed to use WLAnalytics's
- (void) log:(NSString*)message withMetadata:(NSDictionary*)metadata;
(right?)
How can I manage #2? Should I just log the screen ID (using the method above) every time a transition occurs, and expect the last logged id to be passed when the crash log is sent? Or is there any other way to add custom information to crash logs?
Correct you can follow Custom Data, Custom Charts here https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/7.0/moving-production/operational-analytics/
Crash log is detected and sent automatically post crash next time app is started. There is no way to add custom data to that report. Usually the place where the error happen could be deduced form the crash data stack, if this is not sufficient, you can apply the technique you are describing.
I am getting the following warning:
[Crashlytics:Crash] WARNING: the user prompt feature is enabled. As of
Crashlytics 3.0.0, implementing a user prompt is the application's
responsibility. See Crashlytics.h's notes about
-crashlyticsDidDetectReportForLastExecution:completionHandler:
appearing in my app's log when I run it with Xcode. It looks like the version of Crashlytics I'm using is 3.0.8 (from the info.plist file in the Crashlytics.framework).
Here's the relevant doc from the Crashlytics.h file:
/**
*
* Called when a Crashlytics instance has determined that the last execution of the
* application ended in a crash. This is called synchronously on Crashlytics
* initialization. Your delegate must invoke the completionHandler, but does not need to do so
* synchronously, or even on the main thread. Invoking completionHandler with NO will cause the
* detected report to be deleted and not submitted to Crashlytics. This is useful for
* implementing permission prompts, or other more-complex forms of logic around submitting crashes.
*
* Failure to invoke the completionHandler will prevent submissions from being reported. Watch out.
*
* Just implementing this delegate method will disable all forms of synchronous report submission. This can
* impact the reliability of reporting crashes very early in application launch.
*
**/
- (void)crashlyticsDidDetectReportForLastExecution:(CLSReport *)report completionHandler:(void (^)(BOOL submit))completionHandler;
From the warning, it would seem that I wouldn't get the usual "Send Crash Report?" prompt in my app. HOWEVER, I do get this after a crash. That is, it does not seem necessary for me to implement this UI. So, what gives? Is this warning really a mis-said warning that we'll have to do our own UI for this Send Crash Report prompt in the future?
I've also looked at docs https://dev.twitter.com/crashlytics/ios
and http://support.crashlytics.com/knowledgebase/topics/14721-crashlytics-sdk-for-ios
but can't find anything talking about a change since 3.0.0.
Ideas?
Mike from Fabric here.
With SDK 3.0, we added more fine-grained control over how to handle crash report submission so that you, and other developers, can display the alert or not however you want to. If you want to implement your own dialog, turn off the privacy dialog in the Fabric dashboard and you use the call provided to do that.
If you want to continue to use the privacy dialog Fabric provides, you can, but I'd encourage you to create a new one as it's more flexible and can be customized to the UI of your application.
The main idea is to catch the crash log (or the reason of the error) and send it to a server.
I know that iTunes does log the crashes from the users' devices but I need to find if there's a way to get it and store it on our server.
I was trying "PlCrashReporter" and i finished implementing it (as they did on this link https://www.plcrashreporter.org/documentation/api/v1.0/example_usage_iphone.html).
Problem
The function applicationDidFinishLaunching is not called when the crash occurs.
Am I on the right track?
Is there a specific function which is called upon a crash in AppDelegate ?
Thanks in advance
EDIT
I've also tried the solution of the following question:
iOS crash log catch, debug info.. Catch and send via email to the Dev team
It actually works but there are some errors that are cause by Swift and not Objective-C (Like Error while unwrapping optional value) were not caught..
Any suggestions?
You should use Crashlytics. You then can use a custom web hook to receive the crash reports.
I want to exit my application programatically, I googled, some people suggesting to use exit(1), but apple is not supporting that I guess. If it is the case, How do I exit my application programatically. Any helps appreciated.
exit(0); will work but don't use it
You shouldn't force close an app as the standard way to terminate an application is to press the home button (or use the multitasking bar)
Don’t Quit Programmatically
Never quit an iOS application programmatically because people tend to
interpret this as a crash. However, if external circumstances prevent
your application from functioning as intended, you need to tell your
users about the situation and explain what they can do about it.
Depending on how severe the application malfunction is, you have two
choices.
Display an attractive screen that describes the problem and suggests a
correction. A screen provides feedback that reassures users that
there’s nothing wrong with your application. It puts users in control,
letting them decide whether they want to take corrective action and
continue using your application or press the Home button and open a
different application
If only some of your application's features are not working, display
either a screen or an alert when people activate the feature. Display
the alert only when people try to access the feature that isn’t
functioning.
Source
I believe u are not reading the comment properly thus posting the answer for ur question here:
"Simply Don't do that. as apple does not allow application to crash like that."
look at here. How do I exit my iOS app gracefully after handling a Local Notification and here Exit application in iOS 4.0 there are fare discussion over here.
After the release of iOS4, multitasking(new feature) was added by APPLE. This feature enabled the users to keep the app into suspended state in the background if in between he has to do some other activity(e.g. picking up phone call). So Apple considers your app should be maintained in the background until the user deletes the application from the background. And after this if you want to exit use exit(0);, using this would further lead to rejection from AppStore
Here's a wrong way to accomplished exit function in your app. This is coming to mind when I read your question, never applied anywhere, so be careful if you'll gonna implement this!
- (void) exitApp
{
NSArray *array = [[[NSArray alloc] init] autorelease];
NSLog(#"%#",[array objectAtIndex:10]); //will crash here, looks like exit.
}
P.S. You can put this code inside your UIAlertView asking exit confirmation like Do you really want to exit?. In YES button pressed you can call [self exitApp]; User think that he'll exit from the app.