Skip to content

Conversation

@ghenry22
Copy link
Contributor

@ghenry22 ghenry22 commented Nov 8, 2017

This stops wkwebview from instantly stopping all javascript processes when app is sent to the background by attaching it to a key window so that it is still seen as "active" even when in the background vs the default of instantly being considered inactive as it has no active window attached.

Makes it behave the same as UIWebview when app is sent to the background and removes the need for the background mode plugin making things more predictable for developers.

This DOES NOT keep the app alive beyond the normal OS enforced limits for background run time etc, you still need to have an appropriate background capability enabled in xcode and if you app is actually idle it will still be suspended exactly as it should.

@ghenry22
Copy link
Contributor Author

This update solves the problem most of the time but wkwebview can still be suspended overly eagerly when it is considered to be idle, which would be ideal for a native app that was just showing a webpage but is not good for hybrid apps that rely upon the webview for processing.

If you were polling location every 5-10 seconds then this PR alone would probably do the job. In my case I am playing audio in the background so it may be 5 minutes or more between activity in the webview as once a file is playing there is nothing else to do until the next track needs to start and wkwebview can sometimes be suspended causing play back to stop until the app is brought back to the foreground.

I have found two possible solutions that add to this pull request that I am currently testing. I prefer option 1 as it seems

  1. expose and set the configuration._alwaysRunsAtForegroundPriority property to true so that wkwebview doesn't get de-prioritised too aggressively when in the background. This is the method that the background mode plugin uses. In this case though don't "fake" background audio like the background plugin does, apps that genuinely use audio/geolocation etc should work as they generate legitimate background activity. This way we aren't breaching any app store requirements.

  2. implement a native timer that performs a simple task using wkwebview to create activity. Listen for background / foreground changes and start the timer only when in the background. You would still need a valid background capability in xcode and still need to be performing that activity (ie playing audio), the timer would simply stop wkwebview being suspended if you have a longer interval between your tasks. Again this should be an appstore friendly approach.

tie background operation to config.xml WKEnableBackground setting.
Default background mode to NO which will immediately suspend GCDwebserver and allow wkwebview to be eagerly suspended if the OS wants to.
@ghenry22
Copy link
Contributor Author

I have been testing option 1 above for the last day and it has been working consistently well so have updated this PR with an additional commit.

I have tied background operation to the WKEnableBackground preference in config.xml with it defaulting to off, this lines up with the changes for GCDWebserver background operation also being tied to this preference in my other complimentary PR.

There should be no further need for the background mode plugin once these PR's are merged.

Note: This does NOT artificially keep your app alive if it is idle, it can and will still be suspended by the OS if it is truly idle in the background. This simply attaches to a keywindow so that wkwebview is still considered to be active in the background and not instantly frozen and then adds the same config parameter as the background plugin does to allow for ongoing processing in the background. Without the second part the OS can be overly eager in deciding your app is idle as discussed in earlier comments.

This does NOT spoof activity by playing silent audio like the background mode plugin. You still need a legitimate reason for background activity, the associated capability enabled in xcode and actual activity of that type for your app.

What this does do is allow you too play audio in the background, even long running audio with your app being suspended between audio tracks, or to poll for location, or conduct background fetch tasks with appropriate spacing in between activities without being incorrectly suspended.

This removes the reasons for the background mode plugin potentially causing app store rejections.

@ghenry22 ghenry22 changed the title attach wkwebview to keywindow so it stays active in background Allow wkwebview to continue running (and processing javascript!) when app is in the background Nov 15, 2017
@ghenry22
Copy link
Contributor Author

ghenry22 commented Nov 15, 2017

I have a fork with all 3 of my submitted PR's integrated for anyone that wants to try it
just do
ionic cordova plugin add https://github.com/ghenry22/cordova-plugin-ionic-webview#integratedFixes

in your config.xml you can set these new preferences

use dark keyboard appearance on iOS, defaults to false if not specified

<preference name="KeyboardAppearanceDark" value="false" />

set a custom port, defaults to 8080 if not specified, ensure to update your <allow-navigation> value to match the new port.

<preference name="WKPort" value="8534" />

enable background mode, defaults to false if not specified

<preference name="WKEnableBackground" value="true" />

@ghenry22
Copy link
Contributor Author

FYI - I have built tested and submitted updates for several of my own apps using my fork with all commits from the 3 PR's that I have open. All updates have been accepted and published to the app store without issue.

@sithwarrior
Copy link

Looks promising @ghenry22 , I will test it for our usecase - background notification handling sometime next week.

@alexhisen
Copy link

@ghenry22 Could a similar change be made to the original https://github.com/apache/cordova-plugin-wkwebview-engine? (we can't use the Ionic version because code-push doesn't work with it)

I've also found that background JS execution in WKWebView is incredibly slow compared to UIWebView (our use case is Bluetooth LE data transfer). Does this change help with that?

Thanks.

@cfmjohn cfmjohn mentioned this pull request Jan 17, 2018
@cryo243
Copy link

cryo243 commented Mar 7, 2018

@ghenry22, I had to do the same for our use case to prevent the webview from being suspended since our app is being woken up by polling location every 5 - 10 seconds. The app used to hang on the splashscreen. However all I did was to add this configuration option GCDWebServerOption_AutomaticallySuspendInBackground:@(NO) in the CDVWKWebViewEngine.m file as mentioned in swisspol/GCDWebServer#144. Isn't that enough to prevent the webserver for being suspended? The reason why I am asking is because since then the issue has been resolved but we are seeing another issue which I suspect might be introduced because of that configuration. But I can't confirm it yet.

@ghenry22
Copy link
Contributor Author

ghenry22 commented Mar 8, 2018

@cryo243 - that isn't enough on it's own for a few reasons.

  1. that change keeps the webserver running in the background but the webview still stops processing any javascript the instant the app goes into the background.

  2. you also need to keep the webview from immediately suspending when the app is backgrounded, this returns normal app behaviour where it will have some processing time in background and if you have background task capabilities enabled the app will not be suspended by the OS until it is idle. This just allows normal compliant app behaviour. The background plugin that people are using enables the background processing but ALSO fakes background audio to try and stay active forever, which is a bad behaviour and should be avoided. The background plugin is not needed when using this wkwebview fork.

  3. There is a known bug with gcdwebserver when it either starts in the background OR a socket closes when in the background that when the app comes back to the foreground the socket will not be reconnected so you will get errors accessing any content on the gcdwebserver. There is a PR against GCDwebserver project for this, I have merged that fix also into this fork of the webview.

SO with this fork your app can run in the background, as it should, the OS can still suspend it when it wants to and it honors background capabilities. You can also go from background to foreground and the GCDwebserver will CHECK for any TCP socket errors and if it finds an error will reconnect the socket so you don't get connection errors immediately after coming back to the foreground.

@cryo243
Copy link

cryo243 commented Mar 8, 2018

Thanks @ghenry22 . Number 3 is exactly what we were experiencing. When the app is brought forward, local images won't display sometimes.

@ghenry22
Copy link
Contributor Author

ghenry22 commented Mar 8, 2018

@cryo243 yeh that is the bug with GCDwebserver where it doesn't try to reconnect a disconnected socket on resume

It's fixed in my branch.

@mlynch
Copy link
Contributor

mlynch commented Apr 1, 2018

Thanks, just merged #79 which had some keyWindow changes, but not all the stuff in this PR. Will leave this open for later

@ghenry22
Copy link
Contributor Author

ghenry22 commented Apr 2, 2018

@mlynch, all these PR's do is allow the webview to continue processing javascript when in the background UNTIL the OS decides to suspend it as with any other app. Without this any app that has any kind of background processing will not work. One of my app is a music player so for me without these changes I could not use the ionic fork of wkwebview.

There are also fixes to GCDWebserver incorporated here. There is a known bug with GCDwebserver which has been open for some time where sockets can enter an error state while in the app is in the background and are not checked for errors on resume so the webview has a dead socket and cannot retrieve any resources from the GCDwebserver.

There is an open PR against GCDwebserver for some time with fixes for this. I have incorporated the basics of that PR into this work as well as I was observing that issue where my app would come back from background mode and, for example, ionicons and locally storage images would just show a blank square or not found icon until the app was hard closed and restarted to force the tcp connection to the webserver to be reset.

@Maqix
Copy link

Maqix commented Apr 9, 2018

Hi @ghenry22 , my app has exactly the problem described by you. When it is in the background for about a day, it will remain stuck on the splashscreen, probably due to the GCDWebServer bug. This bug drove me crazy for months, and when I found your fork I thought I had finally found the solution. I replaced the Ionic WebView with yours and put it into production, but my users still complain about this bug. So I ask you, since you worked on it, did you find a way to faithfully reproduce the bug? A series of steps that manifest it? I have tried many different things, but I can not reproduce it systematically, the only way I have is not to use the app for a couple of days and see that it does not open. I ask as I can not reproduce it, I can not understand when it's solved, and my project manager keeps asking for information. My app does not make location or audio background work, it have only the OneSignal plugin for push notification (which I think do some stuff in background).

@ghenry22
Copy link
Contributor Author

ghenry22 commented Apr 9, 2018

I doubt any app will remain running in the background for a day without the OS killing it. This fork does not override the default OS app suspension behaviour when it considers the app idle so you need to have legitimate background activity to keep it alive. This is usually background audio or Geo-location. I don’t think intermittently issuing notifications will do it.

As for getting stuck at the splash screen get safari connected up so you can get debug logs and try to reproduce and see what it is hanging on, this is not an issue I have seen before.

@Maqix
Copy link

Maqix commented Apr 9, 2018

For me it's fine that the SO kills my app at some point in time, the only thing I want is that then it starts and does not remain stuck on the splashcreen. The bug on the GCDWebServer that does not reopen the failed connections seems to be responsible for this.

I think it's exactly the problem described by @cryo243 in #45 (comment)

Do you have solved the bug in GCDWebServer?
I have installed the 'master' branch of your fork, does it include the fix?

Is this the commit that introduce it? ghenry22@526b031

@ghenry22
Copy link
Contributor Author

ghenry22 commented Apr 9, 2018

That reconnection bug is fixed in this fork, you just have to make sure to set the enable background setting in config.xml .

Again though this shouldn’t really cause an issue with the splash screen, If you could capture whatever error is being thrown when I gets stuck that might help to narrow down the problem you are having.

@Maqix
Copy link

Maqix commented Apr 9, 2018

I tried in many ways to get the error, but starting the app from XCode never shows the bug, and I can not connect the safari debugger until the app does not start, and at that time the console is gone. ..

I set <preference name = "WKEnableBackground" value = "true" /> ... I noticed that you also created the preference for the port <preference name = "WKPort" value = "8534" />, which is it its purpose?

I think the problem is this -> #57 (comment)

@cryo243
Copy link

cryo243 commented Apr 9, 2018

@Maqix, maybe a suggestion to reproduce the error. Run your app once and then force close it (on iOS just swipe it away) and don't open it for at least a day. Depending on how often you background service runs and on when the OS decides to kill your app you should be able to see it hanging

@Maqix
Copy link

Maqix commented Apr 9, 2018

Thanks for the answer @cryo243, right now, this is the only way I know to reproduce it, I just wonder if there is a faster method to speed up the debugging cycle (edit, check).

Did you manage to solve it on your side?

EDIT: I just found this, the lock/unlock trick is interesting swisspol/GCDWebServer#292

And this: swisspol/GCDWebServer#299

@iliraga
Copy link

iliraga commented Apr 19, 2018

Any Updates here? We built an app which makes heavy usage of background modes / geolocation and are constantly facing strange issues which seems to be based on the issue described in this PR.

@ghenry22
Copy link
Contributor Author

@iliraga just use my fork here:
ionic cordova plugin add https://github.com/ghenry22/cordova-plugin-ionic-webview

refer to the config.xml settings required in the above posts. This should solve any issues with background usage.

@Maqix
Copy link

Maqix commented Apr 20, 2018

Hi all, I have installed @ghenry22 's fork and the problem is reduced (it still happen, but less times)... Did not find a way to reproduce it in a reproducible way 😞

@iliraga
Copy link

iliraga commented Apr 20, 2018

@ghenry22 How reliable is your fork? We will release a version to the app stores in a couple of days and currently i'm not sure whether to switch to your version or not.

@ghenry22
Copy link
Contributor Author

I’ve had multiple apps in the store for months with it with no issues. Seems solid to me.

@iliraga
Copy link

iliraga commented Apr 22, 2018

Okay thanks @ghenry22 we will submit the version today - it's quite a big project so let's find out whether it will work properly 😃

@ghenry22
Copy link
Contributor Author

It’s really just some small but important fixes to the ionic webview, hope it works for you, it solved my
Problems and made wkwebview an option for me.

@jacquesdev
Copy link
Contributor

@ghenry22 - could you possibly resolve the conflicts on this PR, and then after, if possible @mlynch - could you look at getting this merged?

@ghenry22
Copy link
Contributor Author

ghenry22 commented Jun 5, 2018

@jacquesdev @mlynch If it will actually get merged I will gladly resolve the conflicts that have occured after I submitted this. Otherwise its kind of a waste of time to resolve them just for this to continue to sit here not being merged.

You can use my fork at https://github.com/ghenry22/cordova-plugin-ionic-webview which has my PR's and several others already merged and good to go.

@chinmay-ksolves
Copy link

Hi @cryo243 ,

I have integrated this plugin https://github.com/cryo243/cordova-plugin-ionic-webview the splash screen stuck issue is solved but one new issue is occurring - The application when comes from background to foreground after 2 or 3 hours the application is started but the images which are in assets folder is not displaying on the view.

I need to restart my application manually to load those images.

@cryo243
Copy link

cryo243 commented Nov 14, 2018

Hi @chinmay-ksolves ,
Yes that's because of another issue that I did not cater for in my fixes, which @ghenry22 had a fix for.
please refer to

Thanks @ghenry22 . Number 3 is exactly what we were experiencing. When the app is brought forward, local images won't display sometimes.

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

Successfully merging this pull request may close these issues.

9 participants