Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

App stops rendering after being in the background on iOS 12.2 Beta #293

Closed
equinoxss opened this issue Jan 31, 2019 · 49 comments
Closed

App stops rendering after being in the background on iOS 12.2 Beta #293

equinoxss opened this issue Jan 31, 2019 · 49 comments

Comments

@equinoxss
Copy link

On iOS 12.2 Beta, after our app has been in the background for a minute or 2, we see the following errors in the log.

default	15:33:39.797710 -0800	TIC TCP Conn Destroyed [3:0x2831b5980]
error	15:33:39.797762 -0800	TIC Read Status [3:0x0]: 1:57
error	15:33:39.797813 -0800	TIC Read Status [3:0x0]: 1:57
error	15:33:39.797867 -0800	nw_protocol_boringssl_get_output_frames(1301) <private>[0x102033770] get output frames failed, state 8196
error	15:33:39.797922 -0800	nw_protocol_boringssl_get_output_frames(1301) <private>[0x102033770] get output frames failed, state 8196
error	15:33:39.798184 -0800	TIC Read Status [2:0x0]: 1:57
error	15:33:39.798236 -0800 TIC Read Status [2:0x0]: 1:57
***** error	15:33:40.247471 -0800	Background task expired while holding WebKit ProcessAssertion (isMainThread? 1). *****

When the app is brought back to the foreground, the screen will either go white or just stop rendering and will not respond to taps. Note though that the javascript thread continues to run as we still see console.log statements.

We have tried the plugin versions 2.3.2 and 3.1.1 and the problem still occurs with both versions on iOS 12.2 Beta.

Our app does run in the background (geolocation) and we have in config.xml. If we remove the "WKSuspendInBackground" property from config.xml the issue goes away BUT our background processing (geolocation) does too which is kind of a non-starter for us.

We have tested our code on iOS 11.4 and 12.1 as well. We never see the issue on iOS 11.4. We periodically see the issue on iOS 12.1.

We've seen similar issues (Ticket #251) reported and some have suggested upgrading to 3.1.1 fixed the issue for them on iOS 12.1 but it still happens for us (periodically, as stated above).

cli packages: (/Users/sxsmith/.nvm/versions/node/v8.2.0/lib/node_modules)
    @ionic/cli-utils  : 1.19.2
    ionic (Ionic CLI) : 3.20.0

global packages:
    cordova (Cordova CLI) : 8.0.0

local packages:
    @ionic/app-scripts : 3.2.0
    Cordova Platforms  : android 7.0.0 ios 4.5.5
    Ionic Framework    : ionic-angular 3.9.2

System:
    Android SDK Tools : 26.1.1
    ios-deploy        : 1.9.2
    Node              : v8.2.0
    npm               : 6.4.1
    OS                : macOS
    Xcode             : Xcode 10.1 Build version 10B61

Environment Variables:
    ANDROID_HOME : /Users/sxsmith/Library/Android/sdk

Misc:
    backend : pro
branch-cordova-sdk 3.0.0 "branch-cordova-sdk"
com.adjust.sdk 4.14.0 "Adjust"
com.batch.cordova 2.0.2 "Batch"
cordova-clipboard 1.2.1 "Clipboard"
cordova-custom-config 5.0.2 "cordova-custom-config"
cordova-plugin-add-swift-support 1.7.2 "AddSwiftSupport"
cordova-plugin-advanced-http 1.11.1 "Advanced HTTP plugin"
cordova-plugin-app-version 0.1.9 "AppVersion"
cordova-plugin-appavailability 0.4.2 "AppAvailability"
cordova-plugin-contacts 3.0.1 "Contacts"
cordova-plugin-device 2.0.2 "Device"
cordova-plugin-enable-multidex 0.1.3 "Enable Multidex"
cordova-plugin-facebook4 2.1.0 "Facebook Connect"
cordova-plugin-file 6.0.1 "File"
cordova-plugin-file-transfer 1.7.2-dev "File Transfer"
cordova-plugin-geolocation 4.0.1 "Geolocation"
cordova-plugin-googleplus 6.0.0 "Google SignIn"
cordova-plugin-inappbrowser 3.0.0 "InAppBrowser"
cordova-plugin-ionic-keyboard 2.1.2 "cordova-plugin-ionic-keyboard"
cordova-plugin-ionic-webview 2.3.2 "cordova-plugin-ionic-webview"
cordova-plugin-jumbomode 1.0 "Cordova Jumbo Mode"
cordova-plugin-mixpanel 4.3.0 "Mixpanel"
cordova-plugin-native-services 0.0.1 "NativeServices"
cordova-plugin-splashscreen 5.0.2 "Splashscreen"
cordova-plugin-stripe 1.5.3 "cordova-plugin-stripe"
cordova-plugin-whitelist 1.3.3 "Whitelist"
cordova-plugin-x-socialsharing 5.4.1 "SocialSharing"
cordova-universal-links-plugin 1.2.1 "Universal Links Plugin"
es6-promise-plugin 4.2.2 "Promise"
onymos-plugin-media 1.0.8.3 "OnymosMediaComponent"
@equinoxss
Copy link
Author

Through some sleuthing, we've discovered that this other reported issue (#286) may be the cause of this one. If you remove the following code (line 218) from CDVWKWebViewEngine.m, the problem appears to be fixed.

configuration._alwaysRunsAtForegroundPriority = ![settings cordovaBoolSettingForKey:@"WKSuspendInBackground" defaultValue:YES];

This is the stackcrawl article that got us headed in the right direction: https://stackoverflow.com/questions/54474910/ionic-app-crashes-on-ios-12-2-because-of-alwaysrunsatforegroundpriority

@larschla
Copy link

larschla commented Feb 6, 2019

This is the stackcrawl article that got us headed in the right direction: https://stackoverflow.com/questions/54474910/ionic-app-crashes-on-ios-12-2-because-of-alwaysrunsatforegroundpriority

I'm the creator of the above mentioned post, and as it says, on my end my app does just terminate on startup due to this. XCode gives me this message:

*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<WKWebViewConfiguration 0x105916dc0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key _alwaysRunsAtForegroundPriority.'

I have found out that removing the cordova-plugin-background-mode plugin makes the problem go away, but that's no solution for me in the long run, as i need the functionality this plugin provides.

I also tried removing the line mentioned above, in CDVWKWebViewEngine.m (Which is on line 185 at my end), and XCode still gives me the same message. That makes no sense to me, and may not even be part of the problem. Anyway, I'd love to be pointed in the right direction on this one, as i can't have all my customers that use iPhones have their apps crash once iOS 12.2 comes out publicly.

@giladrom
Copy link

giladrom commented Feb 10, 2019

@larschla same here. Please keep us posted if you find anything.

I can confirm upgrading to 3.1.2 does not fix the problem for me.

@gregavola
Copy link

@larschla I can confirm this happening as well.

@gregavola
Copy link

@larschla i can also confirm we are not using the cordova-plugin-background-mode plugin, so not sure it has anything to do with that.

@jcesarmobile
Copy link
Member

Through some sleuthing, we've discovered that this other reported issue (#286) may be the cause of this one. If you remove the following code (line 218) from CDVWKWebViewEngine.m, the problem appears to be fixed.

configuration._alwaysRunsAtForegroundPriority = ![settings cordovaBoolSettingForKey:@"WKSuspendInBackground" defaultValue:YES];

But if you remove that line, does your app keeps running code while in background?

@giladrom
Copy link

When I set WKSuspendInBackground to true in config.xml, the problem goes away but so does background operation (which is a must for me).

@jcesarmobile
Copy link
Member

What are your use cases for background operations? and/or the reason for having WKSuspendInBackground set to false?

@gregavola
Copy link

@jcesarmobile If we set it WKSuspendInBackground to true, wouldn't that mean WKWebview would stay up longer and not be killed by normal OS level stuff?

@giladrom
Copy link

@jcesarmobile WKSuspendInBackground:false is required for iBeacon detection.

@jcesarmobile
Copy link
Member

@jcesarmobile If we set it WKSuspendInBackground to true, wouldn't that mean WKWebview would stay up longer and not be killed by normal OS level stuff?

When you set it to true (or don't set it as true is the default value), the WKWebview is paused (not killed) as soon as the app goes into background.

@jcesarmobile WKSuspendInBackground:false is required for iBeacon detection.

The iBeacon detection is done with native code, so you shouldn't really need the WKWebview, unless you do something when the native code detects the beacon and want the WKWebview to execute some code. That's what I'm looking for with my previous question. So, what do you do when the native code detects the iBeacon?

@giladrom
Copy link

@jcesarmobile while iBeacon detection is done with native code, any resulting JS code must use the cordova webview to execute, and since that is not active, nothing actually happens.

@jcesarmobile
Copy link
Member

That's the question. What do you do when an iBeacon is detected?

@giladrom
Copy link

@jcesarmobile Not sure I understand the question - are you asking what my app does with the data?

@jcesarmobile
Copy link
Member

Yeah, I'm interested in knowing what you do when the iBeacon is detected, like, "I send it to the server", or "I show a local notification". I would assume you don't really display something on the webview as it's in background and the user won't see it anyway.

@giladrom
Copy link

@jcesarmobile that is correct. I need to interact with a remote server even if the user isn't anywhere near their phone. That is how it currently works up to iOS 12.1.

@mlynch
Copy link
Contributor

mlynch commented Feb 14, 2019

Okay, there's a few things going on here. First, this API we were using is private and it looks like it's not going to work anymore. Also, the more I dig into this the more I realize it was a hack anyways. When an app is put in the background (speaking about iOS), generally execution is stopped completely, and that goes for any app, native, Ionic, or otherwise.

However, there is an official way to extend the amount of time your app has to run tasks before it is backgrounded (on iOS): You can do this by starting a background task: https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/extending_your_app_s_background_execution_time

In fact, Capacitor has an API available for this: https://capacitor.ionicframework.com/docs/apis/background-task

@jcesarmobile my understanding is that the Capacitor API would let the webview continue to execute for a few more minutes for any last operations you need to fit in before the app is backgrounded. I wonder if a simple solution like BackgroundTask would work for Cordova: https://github.com/ionic-team/capacitor/blob/master/ios/Capacitor/Capacitor/Plugins/BackgroundTask.swift#L12

Periodic Tasks/Background Geolocation/Fetch/etc.

Second, for periodic background tasks, the only way to make that work is to execute code in the native layer. However, that also has access to the native JavaScriptCore engine.

We're currently exploring a way to add a script or function to run periodically when the app is backgrounded. This would likely be the most natural fit in Capacitor as we already export the full JS API for each plugin automatically, so I believe adding support to access those plugins in your background task would be straightforward. For Cordova I wonder if we could expose an exec function, but that I'm less clear on.

Moving forward

So, it seems like this solution was a hack and has finally stopped working. It seems unlikely that Apple will fix it, but there's a possibility they will.

However, we don't want to risk it. It seems like the best, most future-proof solution, is to expand our BackgroundTask concept to allow for extending background time when the app is initially backgrounded, and then adding support for running a script or function periodically for things like background geolocation and data fetching.

@giladrom
Copy link

@mlynch What about apps that need to wake up in the event a BLE device was detected? Will that be supported?

@mlynch
Copy link
Contributor

mlynch commented Feb 14, 2019

That's one of apple's "Background Modes" capability options, so yes in theory: https://developer.apple.com/documentation/corelocation/getting_the_user_s_location/handling_location_events_in_the_background

@giladrom
Copy link

@mlynch My problem is as follows: If Apple doesn't fix it and the "yes in theory" turns out to be a "no", my app stops working come iOS 12.2.

So I'm sitting here needing to decide if I should completely abandon Ionic/Cordova and rewrite my entire application in Swift before 12.2 drops, or migrate to Ionic4/Capacitor and hope for the best.

@gregavola
Copy link

@mlynch So what is the fix here - setting that configuration false?

What we are seeing is that wkwebvjew doesn’t suspend at all in ios12.2 - meaning it’s a complete white screen after resuming from the background. That’s the issue I’m trting to resolve.

@mlynch
Copy link
Contributor

mlynch commented Feb 14, 2019

@giladrom how frequently and for how long does your app communicate with that server? This configuration option didn't keep the app from being backgrounded completely, so it's not like you were able to run constant background operations with that configuration option anyways. I bet we could get the BackgroundTask feature in Capacitor added to this plugin as a short term option.

@gregavola what was your use case for this option? Were you setting it to false? Or are you seeing it happen even with WKSuspendInBackground removed from the config?

I think it's clear we need to just remove that line from the code as soon as possible, as even if Apple fixes it it's a private API and people are getting app store review warnings about it now.

@giladrom
Copy link

giladrom commented Feb 14, 2019

@mlynch The app wakes up and updates a remote database entry, and then goes back to sleep. 2-3 seconds maybe. Frequency depends on the amount of beacons detected, but there's no requirement for long background execution. Without this option, it never wakes up.

@gregavola
Copy link

@mlynch we are setting it to false right now - which prevents the app from being killed in the background. In 12.1.x - app stays “open” in the background and resumed to the app current. Without the setting - we saw the app restarting (not white screen of desth) for a short period of time being the background.

With it being removed - won’t the app just get killed like it used before we added it?

@giladrom
Copy link

@gregavola it will still "resume" properly after a short while in the background but it will definitely get killed much faster.

@gregavola
Copy link

@giladrom that’s the issue I am referring to @mlynch - the time it takes for the app to get killed is pretty bad, this previously helped a lot.

@mlynch
Copy link
Contributor

mlynch commented Feb 14, 2019

@giladrom and you were doing the remote database entry update from the webview in JS?

@gregavola I've been doing some testing tonight without that setting and the private API, and so far I haven't seen any out of the ordinary app reloads after backgrounding and coming back to the app several minutes later (iPhone X). I wonder if dev mode is different though...

@giladrom
Copy link

@mlynch from an Ionic Provider using angular firestore.

@mlynch
Copy link
Contributor

mlynch commented Feb 21, 2019

We released several fixes for this last week. Upgrade to 4.0 if you're able to drop the webserver (and iOS 10), or use the latest 2.x if you need to support iOS 10 still. Both have a fix for this issue.

@mlynch mlynch closed this as completed Feb 21, 2019
@giladrom
Copy link

@mlynch Do these fixes resolve the background operation issue? All I'm seeing in the commit log is WKSuspendInBackground being removed as a preference.

@mlynch
Copy link
Contributor

mlynch commented Feb 21, 2019

@giladrom - @jcesarmobile tested similar use cases and they appear to work just fine without the private API, right Julio?

Also @gregavola we tested quite a bit whether this change will cause apps to reload more frequently when backgrounded and returned to, and so far they don't behave any differently from any other pure native app. That very well could have been an issue on an older version of iOS.

@giladrom
Copy link

giladrom commented Feb 21, 2019

@mlynch in my testing absolutely nothing happens without that API - which is the reason I enabled it in the first place.

EDIT: Tested again with the new iOS 12.2 Beta 3 and the new version of the plugin - still broken and does not wake up when in range of a beacon.

@jcesarmobile
Copy link
Member

I tested silent push notifications and they woke up the app and the webview was able to execute the code.
I didn’t test iBeacons because I don’t have any, but shouldn’t be different
In the past plugins weren’t working because the bridge code had a setTimeout and code in setTimeout or setInterval doesn’t work when in background, but that was changed a few months ago.

@giladrom
Copy link

giladrom commented Feb 21, 2019 via email

@jcesarmobile
Copy link
Member

I think I know what the problem is, I'm just putting a console.log when the push is received, and that is in fact printed in the console.
But now I have tried with XHR and fetch calls to a local server.
XHR calls have never worked on my sample app, fetch has worked sometimes, but not always.
What always seem to work is http plugin (maybe because it uses native code?)

Anyway, it's hard to test with silent pushes as the system decides if it want to forward them to the app, and not always do. If you check the device logs, you can see some Daemon Canceling Activities messages, which means the device received the push but didn't start the app.

Do you have some sample for the iBeacons? or can you check in your app if using http plugin works when in background?

@giladrom
Copy link

@jcesarmobile After testing for the last day or so, it would appear that the app DOES wake up in the background when it detects beacons, only does so somewhat less frequently (hard to tell exactly, but will keep testing).

You can use the Radius Locate app to both detect and emulate a beacon https://store.radiusnetworks.com/products/locate-ibeacon-app.

I'm still interested in knowing how you're sending out silent notifications, it would help me cross test and verify.

@coderroggie
Copy link

@mlynch will there be a release for the 2.x branch?

@Ionitron
Copy link
Collaborator

Ionitron commented Feb 22, 2019 via email

@jcesarmobile
Copy link
Member

@coderroggie sorry, I forgot to create the release on github, but 2.4.0 was published on npm last Monday. Just created the github release too.

@giladrom I use phonegap-plugin-push and use NWPusher to send this payload:

{
   "aps" : {
      "content-available" : 1
   },
   "acme1" : "bar",
   "acme2" : 42,
  "notId": 123 
}

The important part is the content-available with 1 as value and the notId as it's used by push plugin to finish the app when done.

Then my app has this code that hits the server with http plugin and call push.finish (this is important as if you don't call it the time you receive when the app wakes up expires, and if it expires a few times the system can think that you app is wasting too much battery and might not send more silent pushes to it.

push.on('notification', function (data) {
            cordova.plugin.http.get('http://192.168.1.138:8000/api', {},
             { }, function(response) {
                console.log(response.status);
                push.finish(
                    () => { console.log('finish success'); },
                    () => {console.log('finish error');},
                    data.notId
                  );
              }, function(response) {
                console.error(response.error);
                push.finish(
                    () => { console.log('finish success'); },
                    () => { console.log('finish error'); },
                    data.notId
                  );
              });
            console.log('push received');
        });

@coderroggie
Copy link

@jcesarmobile @mlynch thanks :)

@BorntraegerMarc
Copy link

BorntraegerMarc commented Feb 27, 2019

@jcesarmobile It's weird that the phonegap-plugin-push seems to work for you with the new plugin version. I do not even get to my console log:

pushObject.on('notification').subscribe((notificationEvent: NotificationEventResponse) => {
    console.log('XXX 1');
});

I can confirm:

  • My JS code is executed properly with v2.3.1 with WKSuspendInBackground=false
  • My JS code is not executed with v2.3.1 with WKSuspendInBackground=false
  • My JS code is not executed with v2.4.0

PS: I'm using VoIP push on iOS & I was testing this behaviour while my app was killed (double clicked on home and swiped up).

@mlynch How would one implement "Extending Your App's Background Execution Time" with cordova (without capacitor)? Based on the documentation I only see a way in native code.

EDIT: Created a new issue to track this: #317

@gregavola
Copy link

@mlynch I will say that at least in 12.1.X, we see the white screen all the time with low power mode (just like it used it). - without this settings. My hope is when 12.2 drops, it will be better.

@BorntraegerMarc
Copy link

@gregavola which version are you using? Generally with WKSuspendInBackground=false this bug shouldn't happen

@gregavola
Copy link

@BorntraegerMarc That setting has been removed from the build because of the fact that is a private API.

@BorntraegerMarc
Copy link

@gregavola yeah I know. Just thought if you use an earlier version 🙂

@gregavola
Copy link

@BorntraegerMarc The earlier version appears to be broken in Beta iOS 12.x and earlier versions have a vulnerability: https://ionic.zendesk.com/hc/en-us/articles/360015176994-2019-01-03-Security-Alert-for-cordova-plugin-ionic-webview

@ghenry22
Copy link
Contributor

I have submitted a PR that resolves the crash and restores suspendinbackground functionality with compatibility for ios12.2+ and for earlier versions. Basically what broke is that:

_alwaysRunsAtForegroundPriority
changed to:
alwaysRunsAtForegroundPriority

So I have implemented a version check and correct behaviour for each using the same solution as was proposed in discussion of the issue for the backgroundmode plugin here:
katzer/cordova-plugin-background-mode#419

Not sure about the white screen and other issues but this restores basic background operations for those who need it. For example one of my apps is an audio player and I need to queue the next track and the end of the current one. I can't do this smoothly without background processing in JS and this is a valid and acceptable background use case for apps.

Without the background JS processing my option would be to rewrite the whole app or at least very large parts of it in native code for each platform which is not a path I am interested in going down.

schoenkaft added a commit to schoenkaft/cordova-plugin-background-mode that referenced this issue Apr 10, 2019
Note that this was a wildly used hack, which stopped working. This is a quick fix, but it's not future proof.

See: katzer#419
See: ionic-team/cordova-plugin-ionic-webview#293
schoenkaft added a commit to schoenkaft/cordova-plugin-background-mode that referenced this issue Apr 10, 2019
Note that this was a wildly used hack, which stopped working. This is a quick fix, but it's not future proof.

See: katzer#419
See: ionic-team/cordova-plugin-ionic-webview#293
@gregavola
Copy link

gregavola commented Apr 10, 2019 via email

@BorntraegerMarc
Copy link

FYI link here: #343 for @ghenry22's PR

rodrigovrm added a commit to refurbify/cordova-plugin-background-mode that referenced this issue Apr 24, 2019
Fixes the hack for the private setting alwaysRunsAtForegroundPriority

see: katzer#419
see: ionic-team/cordova-plugin-ionic-webview#293
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants