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

feat(ios): new background tasks api for iOS 13+ #11689

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

sgtcoolguy
Copy link
Contributor

@sgtcoolguy sgtcoolguy commented May 5, 2020

JIRA: https://jira.appcelerator.org/browse/TIMOB-27864

Description:
This is an attempt to get Jan's feature branch working locally. I'm not sure if these changes are valid and everything we need or not. Jan did all the heavy lifting!

The main change here was to make TiPerformBlock explicitly run the block on the KrollContext's "jsThread". Basically we try and keep track of what NSThread started up the context/JS environment and we try and route calls to run on that thread for js running in that context. In the past this was easier as we explicitly forced the js engine/context to be on the main thread, so we'd typically use TiThreadPerformOnMainThread. But if we now have a separate context running in parallel in a background task and try to force the call to happen on main thread, it basically locks.

I used the category here to extend NSThread to make it easy to schedule a block to run on a given NSThread: http://objcolumnist.com/2011/05/03/performing-a-block-of-code-on-a-given-thread/

Using this code I was able to get the Xcode project with the task running on my iPhone XR - including the polyfills/extensions in ti.task.js startup.

@build
Copy link
Contributor

build commented May 5, 2020

Fails
🚫

🔬 There are library changes, but no changes to the unit tests. That's OK as long as you're refactoring existing code, but will require an admin to merge this PR. Please see README.md#unit-tests for docs on unit testing.

Warnings
⚠️

🔍 Can't find junit reports at ./junit.*.xml, skipping generating JUnit Report.

Messages
📖 ✊ The commits in this PR match our conventions! Feel free to Rebase and Merge this PR when ready.

Generated by 🚫 dangerJS against afa2fd9

@sgtcoolguy
Copy link
Contributor Author

For reasons not entirely clear to me, loading the node extensions intermittently cause the task to:

  • not run
  • get to the point of spitting out the log but not finishing the underlying task object
  • fully finish

I keep commenting out sections or not and it's inconsistent in how it responds. My best guess here is maybe it's limiting the run time in some way and sometimes it gets by and sometimes doesn't? I have no idea, but it is driving me mad. So it can run loading the core-js polyfills and regenerator runtime. And if I split up loading our extensions I can usually get it to load the js/ti ones and most of the node extensions (it usually fails when string_decoder and fs are included).

@jquick-axway
Copy link
Contributor

@sgtcoolguy, I have an alternative idea.

Instead of creating a separate JS runtime to execute the task's script in, how about firing an event on the main JS runtime. And on a cold app start, we would queue the tasks to be fired via the TiApp booted method which gives the "app.js" time to add a listener. We can pass a reference to the BackgroundTask proxy via an event argument so that the listener can call its setTaskCompleted() when finished.

And I don't think the background task needs to be ran on a separate thread. Especially since the background task will only be invoked when the app is in the background, which means the main UI thread is pretty much doing nothing. I know our iOS background service is implemented on a separate thread and JS runtime, but it doesn't seem necessary. It would be a lot more convenient for app developers to use if everything was done on the same JS runtime where they can leverage everything they've globally configured in their "app.js".
(Note that Android's service scripts are executed on the main JS runtime too... and I kind of wish they were implemented as events instead.)

Side Note:
Correct me if I'm wrong, but won't the "app.js" and its UI be created on a cold app start when the a background task is launched? Won't the app delegate's didFinishLaunchingWithOptions() method always get called when the app process get launched? I can see we always create our main window there.
https://github.com/appcelerator/titanium_mobile/blob/master/iphone/TitaniumKit/TitaniumKit/Sources/API/TiApp.m#L331

@janvennemann
Copy link
Contributor

janvennemann commented May 28, 2020

@jquick-axway You might think that a background service is run on a separate thread, but actually it is not thanks to this. So starting the new JS runtime actually moves over to the main thread. Part of this PR was to remove this restriction.

Regarding your event idea, i guess we would need to evaluate this. Usually iOS has very strict restrictions regarding resource usage of an app while it is backgrounded. The event stuff might work for short lived tasks like the refreshing data. But the new BackgroundTasks framework has another processing task type, where you can specifically say that the devices needs to be connected to a power source and/or has wifi access before it get's started. If we shift that to the main thread again instead of using the designated background thread, i could imagine that the system just kills the app? I don't now for sure, so we need to check if iOS is fine with running things on the main thread for a background task.

According to the App Launch Sequence the "app.js" will always get called via didFinishLaunchingWithOptions during a cold app boot.

@sgtcoolguy sgtcoolguy modified the milestones: 9.1.0, 9.2.0 Jul 31, 2020
@sgtcoolguy sgtcoolguy modified the milestones: 9.2.0, 10.0.0 Sep 1, 2020
@hansemannn hansemannn removed this from the 10.0.0 milestone Mar 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants