├── .github
├── ISSUE_TEMPLATE
│ ├── 1-bug.yml
│ └── 2-help-wanted.yml
└── workflows
│ └── stale.yaml
├── .gitignore
├── .npmignore
├── .yarnignore
├── CHANGELOG.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── RNBackgroundFetch.podspec
├── android
├── build.gradle
├── libs
│ └── com
│ │ └── transistorsoft
│ │ └── tsbackgroundfetch
│ │ ├── 1.0.4
│ │ ├── tsbackgroundfetch-1.0.4.aar
│ │ ├── tsbackgroundfetch-1.0.4.aar.md5
│ │ ├── tsbackgroundfetch-1.0.4.aar.sha1
│ │ ├── tsbackgroundfetch-1.0.4.aar.sha256
│ │ ├── tsbackgroundfetch-1.0.4.aar.sha512
│ │ ├── tsbackgroundfetch-1.0.4.pom
│ │ ├── tsbackgroundfetch-1.0.4.pom.md5
│ │ ├── tsbackgroundfetch-1.0.4.pom.sha1
│ │ ├── tsbackgroundfetch-1.0.4.pom.sha256
│ │ └── tsbackgroundfetch-1.0.4.pom.sha512
│ │ └── maven-metadata.xml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── transistorsoft
│ └── rnbackgroundfetch
│ ├── HeadlessTask.java
│ ├── RNBackgroundFetchModule.java
│ └── RNBackgroundFetchPackage.java
├── app.plugin.js
├── docs
├── INSTALL-AUTO-ANDROID.md
├── INSTALL-AUTO-IOS.md
├── INSTALL-COCOAPODS-IOS.md
├── INSTALL-EXPO.md
├── INSTALL-LINK-ANDROID.md
├── INSTALL-LINK-IOS.md
├── INSTALL-MANUAL-ANDROID.md
└── INSTALL-MANUAL-IOS.md
├── example
├── .buckconfig
├── .editorconfig
├── .eslintrc.js
├── .gitattributes
├── .gitignore
├── .prettierrc.js
├── .ruby-version
├── .watchmanconfig
├── App.tsx
├── Gemfile
├── README.md
├── __tests__
│ └── App-test.tsx
├── android
│ ├── app
│ │ ├── _BUCK
│ │ ├── build.gradle
│ │ ├── build_defs.bzl
│ │ ├── debug.keystore
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ │ ├── debug
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── fetchdemo
│ │ │ │ └── ReactNativeFlipper.java
│ │ │ └── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── fetchdemo
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── MainApplication.java
│ │ │ │ └── newarchitecture
│ │ │ │ ├── MainApplicationReactNativeHost.java
│ │ │ │ ├── components
│ │ │ │ └── MainComponentsRegistry.java
│ │ │ │ └── modules
│ │ │ │ └── MainApplicationTurboModuleManagerDelegate.java
│ │ │ ├── jni
│ │ │ ├── CMakeLists.txt
│ │ │ ├── MainApplicationModuleProvider.cpp
│ │ │ ├── MainApplicationModuleProvider.h
│ │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp
│ │ │ ├── MainApplicationTurboModuleManagerDelegate.h
│ │ │ ├── MainComponentsRegistry.cpp
│ │ │ ├── MainComponentsRegistry.h
│ │ │ └── OnLoad.cpp
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ └── rn_edit_text_material.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ └── values
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ └── settings.gradle
├── app.json
├── babel.config.js
├── index.js
├── ios
│ ├── .xcode.env
│ ├── FetchDemo.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── FetchDemo.xcscheme
│ ├── FetchDemo.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── FetchDemo
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.mm
│ │ ├── Images.xcassets
│ │ │ ├── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ └── main.m
│ ├── FetchDemoTests
│ │ ├── FetchDemoTests.m
│ │ └── Info.plist
│ ├── Podfile
│ └── Podfile.lock
├── metro.config.js
├── package.json
├── scripts
│ ├── simulate-fetch.sh
│ └── watch
├── src
│ └── Event.ts
├── tsconfig.json
└── yarn.lock
├── expo
└── plugin
│ ├── src
│ ├── androidPlugin.ts
│ ├── iOSPlugin.ts
│ └── index.ts
│ └── tsconfig.json
├── index.d.ts
├── index.js
├── ios
├── RNBackgroundFetch.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata
│ │ └── chris.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── RNBackgroundFetch
│ ├── RNBackgroundFetch+AppDelegate.m
│ ├── RNBackgroundFetch.h
│ ├── RNBackgroundFetch.m
│ └── TSBackgroundFetch.xcframework
│ │ ├── Info.plist
│ │ ├── _CodeSignature
│ │ ├── CodeDirectory
│ │ ├── CodeRequirements
│ │ ├── CodeRequirements-1
│ │ ├── CodeResources
│ │ └── CodeSignature
│ │ ├── ios-arm64
│ │ └── TSBackgroundFetch.framework
│ │ │ ├── Headers
│ │ │ └── TSBackgroundFetch.h
│ │ │ ├── Info.plist
│ │ │ ├── Modules
│ │ │ └── module.modulemap
│ │ │ ├── PrivacyInfo.xcprivacy
│ │ │ ├── TSBackgroundFetch
│ │ │ └── _CodeSignature
│ │ │ ├── CodeDirectory
│ │ │ ├── CodeRequirements
│ │ │ ├── CodeRequirements-1
│ │ │ ├── CodeResources
│ │ │ └── CodeSignature
│ │ ├── ios-arm64_x86_64-maccatalyst
│ │ └── TSBackgroundFetch.framework
│ │ │ ├── Headers
│ │ │ └── TSBackgroundFetch.h
│ │ │ ├── Modules
│ │ │ └── module.modulemap
│ │ │ ├── Resources
│ │ │ ├── Info.plist
│ │ │ └── PrivacyInfo.xcprivacy
│ │ │ ├── TSBackgroundFetch
│ │ │ └── _CodeSignature
│ │ │ ├── CodeDirectory
│ │ │ ├── CodeRequirements
│ │ │ ├── CodeRequirements-1
│ │ │ ├── CodeResources
│ │ │ └── CodeSignature
│ │ └── ios-arm64_x86_64-simulator
│ │ └── TSBackgroundFetch.framework
│ │ ├── Headers
│ │ └── TSBackgroundFetch.h
│ │ ├── Info.plist
│ │ ├── Modules
│ │ └── module.modulemap
│ │ ├── PrivacyInfo.xcprivacy
│ │ ├── TSBackgroundFetch
│ │ └── _CodeSignature
│ │ ├── CodeDirectory
│ │ ├── CodeRequirements
│ │ ├── CodeRequirements-1
│ │ ├── CodeResources
│ │ └── CodeSignature
└── Resources
│ └── PrivacyInfo.xcprivacy
└── package.json
/.github/ISSUE_TEMPLATE/1-bug.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report.
3 | title: "[Bug]: "
4 | labels: ["bug", "triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for taking the time to fill out this support request.
10 | - type: checkboxes
11 | id: terms
12 | attributes:
13 | label: Required Reading
14 | description: "- I have read the [README](../blob/master/README.md) and [Debugging](../blob/master/README.md#debugging-1) section\n- I am aware of the [API Documentation](../blob/master/README.md#api-documentation)\n- I am aware of the [CHANGELOG](../blob/master/CHANGELOG.md)"
15 | options:
16 | - label: Confirmed
17 | required: true
18 | - type: input
19 | id: version
20 | attributes:
21 | label: Plugin Version
22 | description: What version of our software are you running?
23 | placeholder: "Consult your package.json (do not enter 'latest')"
24 | validations:
25 | required: true
26 | - type: checkboxes
27 | id: os
28 | attributes:
29 | label: Mobile operating-system(s)
30 | description: Which mobile operating-system(s) is this issue reported upon?
31 | options:
32 | - label: iOS
33 | - label: Android
34 | - type: input
35 | id: device-info
36 | attributes:
37 | label: Device Manufacturer(s) and Model(s)
38 | description: What is the device model(s) and manufacturer(s)
39 | placeholder: eg Google Pixel 6, iPhone 13 Pro
40 | validations:
41 | required: true
42 | - type: input
43 | id: device-os
44 | attributes:
45 | label: Device operating-systems(s)
46 | description: Affected device operating system
47 | placeholder: eg iOS 18.1, Android 13
48 | validations:
49 | required: true
50 | - type: input
51 | id: framework-version
52 | attributes:
53 | label: React Native / Expo version
54 | description: What version React Native / Expo are you using
55 | placeholder: "eg: 0.76.6, Expo 52 (consult your package.json)"
56 | - type: textarea
57 | id: what-happened
58 | attributes:
59 | label: What happened?
60 | description: Also tell us, what did you expect to happen?
61 | placeholder: Tell us what happened and what did you expect to happen.
62 | validations:
63 | required: true
64 | - type: textarea
65 | id: config
66 | attributes:
67 | label: Plugin Code and/or Config
68 | description: Provide the Config you're using with the `BackgroundFetch.configure(config)` method along with any other relevant code.
69 | placeholder: "Paste your Config or code here, eg: BackgroundFetch.configure(config).\n\nYour code will be automatically syntax-highlighted"
70 | render: typescript
71 | validations:
72 | required: true
73 | - type: textarea
74 | id: logs
75 | attributes:
76 | label: Relevant log output
77 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
78 | placeholder: "include iOS / Android logs\n- $ adb logcat -s TSBackgroundFetch:V\n- ios XCode logs"
79 | render: shell
80 |
81 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/2-help-wanted.yml:
--------------------------------------------------------------------------------
1 | name: Help Wanted
2 | description: I need assistance
3 | title: "[Help Wanted]: "
4 | labels: ["triage"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for taking the time to fill out this support request.
10 | - type: checkboxes
11 | id: terms
12 | attributes:
13 | label: Required Reading
14 | description: "- I have read the [README](../blob/master/README.md) and [Debugging](../blob/master/README.md#debugging-1) section\n- I am aware of the [API Documentation](../blob/master/README.md#api-documentation)\n- I am aware of the [CHANGELOG](../blob/master/CHANGELOG.md)"
15 | options:
16 | - label: Confirmed
17 | required: true
18 | - type: input
19 | id: version
20 | attributes:
21 | label: Plugin Version
22 | description: What version of our software are you running?
23 | placeholder: "Consult your package.json (do not enter 'latest')"
24 | validations:
25 | required: true
26 | - type: checkboxes
27 | id: os
28 | attributes:
29 | label: Mobile operating-system(s)
30 | description: Which mobile operating-system(s) is this about?
31 | options:
32 | - label: iOS
33 | - label: Android
34 | validations:
35 | required: true
36 | - type: textarea
37 | id: what-happened
38 | attributes:
39 | label: What do you require assistance about?
40 | validations:
41 | required: true
42 | - type: textarea
43 | id: config
44 | attributes:
45 | label: "[Optional] Plugin Code and/or Config"
46 | description: Provide the Config you're using with the `BackgroundFetch.configure(config)` method along with any other relevant code.
47 | placeholder: "Paste your Config or code here, eg: BackgroundFetch.configure(config).\n\nYour code will be automatically syntax-highlighted"
48 | render: typescript
49 | validations:
50 | required: false
51 | - type: textarea
52 | id: logs
53 | attributes:
54 | label: "[Optional] Relevant log output"
55 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
56 | placeholder: "include iOS / Android logs\n- $ adb logcat -s TSBackgroundFetch:V\n- ios XCode logs"
57 | render: shell
58 | validations:
59 | required: false
60 |
61 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yaml:
--------------------------------------------------------------------------------
1 | name: Close inactive issues
2 | on:
3 | schedule:
4 | - cron: "30 1 * * *"
5 |
6 | jobs:
7 | close-issues:
8 | runs-on: ubuntu-latest
9 | permissions:
10 | issues: write
11 | pull-requests: write
12 | steps:
13 | - uses: actions/stale@v5
14 | with:
15 | operations-per-run: 100
16 | days-before-issue-stale: 30
17 | days-before-issue-close: 14
18 | stale-issue-label: "stale"
19 | stale-issue-message: "This issue is stale because it has been open for 30 days with no activity."
20 | close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
21 | days-before-pr-stale: -1
22 | days-before-pr-close: -1
23 | repo-token: ${{ secrets.GITHUB_TOKEN }}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | package-lock.json
30 |
31 | # Dependency directories
32 | node_modules
33 | jspm_packages
34 |
35 | # Optional npm cache directory
36 | .npm
37 |
38 | # Optional REPL history
39 | .node_repl_history
40 |
41 | .DS_Store
42 |
43 | android/build
44 | android/*.iml
45 |
46 | xcuserdata/
47 | android/.gradle
48 |
49 | android/local.properties
50 |
51 | # Expo build
52 | expo/plugin/build/**
53 |
54 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | docs/
3 | example/
4 | *.md
5 | node_modules
6 | .github/
7 | expo/plugin/src
8 | expo/plugin/tsconfig.json
9 |
--------------------------------------------------------------------------------
/.yarnignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | docs/
3 | example/
4 | *.md
5 | node_modules
6 | .github/
7 |
8 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 | ## Your Environment
16 | * Plugin version:
17 | * Platform: iOS or Android
18 | * OS version:
19 | * Device manufacturer / model:
20 | * React Native version (`react-native -v`):
21 | * Plugin config
22 |
23 | ## Expected Behavior
24 |
25 |
26 | ## Actual Behavior
27 |
28 |
29 | ## Steps to Reproduce
30 |
31 | 1.
32 | 2.
33 | 3.
34 | 4.
35 |
36 | ## Context
37 |
38 |
39 | ## Debug logs
40 |
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Transistor Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/RNBackgroundFetch.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.cocoapods_version = '>= 1.10.0'
7 | s.name = 'RNBackgroundFetch'
8 | s.version = package['version']
9 | s.summary = package['description']
10 | s.description = <<-DESC
11 | iOS BackgroundFetch API Implementation
12 | DESC
13 | s.homepage = package['homepage']
14 | s.license = package['license']
15 | s.author = package['author']
16 | s.source = { :git => 'https://github.com/transistorsoft/react-native-background-fetch.git', :tag => s.version }
17 |
18 | s.requires_arc = true
19 | s.platform = :ios, '8.0'
20 |
21 | s.dependency 'React-Core'
22 | s.preserve_paths = 'docs', 'CHANGELOG.md', 'LICENSE', 'package.json', 'RNBackgroundFetch.ios.js'
23 | s.source_files = 'ios/RNBackgroundFetch/RNBackgroundFetch.h', 'ios/RNBackgroundFetch/RNBackgroundFetch.m'
24 | s.vendored_frameworks = 'ios/RNBackgroundFetch/TSBackgroundFetch.xcframework'
25 | s.resource_bundles = {'TSBackgroundFetchPrivacy' => ['ios/Resources/PrivacyInfo.xcprivacy']}
26 | end
27 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def DEFAULT_COMPILE_SDK_VERSION = 31
4 | def DEFAULT_TARGET_SDK_VERSION = 30
5 | def DEFAULT_MIN_SDK_VERSION = 16
6 | def DEFAULT_LIFE_CYCLE_RUNTIME_VERSION = "2.4.1"
7 | def DEFAULT_LIFE_CYCLE_EXTENSIONS_VERSION = "2.2.0"
8 |
9 | def safeExtGet(prop, fallback) {
10 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
11 | }
12 |
13 | android {
14 | if (project.android.hasProperty("namespace")) {
15 | namespace("com.transistorsoft.rnbackgroundfetch")
16 | }
17 |
18 | compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
19 |
20 | defaultConfig {
21 | minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
22 | targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
23 | consumerProguardFiles 'proguard-rules.pro'
24 | versionCode 1
25 | versionName "1.0"
26 | }
27 | compileOptions {
28 | sourceCompatibility JavaVersion.VERSION_1_8
29 | targetCompatibility JavaVersion.VERSION_1_8
30 | }
31 | }
32 |
33 | repositories{
34 | mavenCentral()
35 | maven {
36 | url './libs'
37 | }
38 | }
39 |
40 | dependencies {
41 | def lifeCycleRuntimeVersion = safeExtGet('lifeCycleRuntimeVersion', DEFAULT_LIFE_CYCLE_RUNTIME_VERSION)
42 | def lifeCycleExtensionsVersion = safeExtGet('lifeCycleExtensionsVersion', DEFAULT_LIFE_CYCLE_EXTENSIONS_VERSION)
43 |
44 | implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
45 | implementation(group: 'com.transistorsoft', name:'tsbackgroundfetch', version: '+')
46 | // LifeCycleObserver
47 | implementation "androidx.lifecycle:lifecycle-runtime:$lifeCycleRuntimeVersion"
48 | implementation "androidx.lifecycle:lifecycle-extensions:$lifeCycleExtensionsVersion"
49 | }
50 |
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/transistorsoft/react-native-background-fetch/f682dbd0e1d4e1c943d032b66246e40e118ebec0/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar.md5:
--------------------------------------------------------------------------------
1 | 8179b611fd9f6fb07357b9b7dfde781b
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar.sha1:
--------------------------------------------------------------------------------
1 | eb0a4f6a810f05eec51d5b92b846a70693c52be6
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar.sha256:
--------------------------------------------------------------------------------
1 | 7678cef9a5ff3942720e2839aa82473a81e06ba5e0ca672cfaa2100a98b66468
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.aar.sha512:
--------------------------------------------------------------------------------
1 | 7fa2f89c2a79cf5ff6070e3986914fff7f46d91dfe40ab21a70875556f429bffb99b085c59b10951063cb717896f94fb7a478611607fb544eb838a87470bea1c
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.pom:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.transistorsoft
6 | tsbackgroundfetch
7 | 1.0.4
8 | aar
9 |
10 |
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.pom.md5:
--------------------------------------------------------------------------------
1 | d17405d8d49a051f96c9e960f7059109
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.pom.sha1:
--------------------------------------------------------------------------------
1 | 1fd4138746b94af71350424a33c0160c154812d9
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.pom.sha256:
--------------------------------------------------------------------------------
1 | 3702c65bb77f6c0741f6005e770968fb015877378f3a1c8b8e7c31f47da65aa1
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/1.0.4/tsbackgroundfetch-1.0.4.pom.sha512:
--------------------------------------------------------------------------------
1 | 820e817adf42044cbab55e028a9d142741ae2b211c829e145813ad720320d92f118136f73835f096123168a18fbabf5c056f3e57fe0f95b403a682ce73854dd7
--------------------------------------------------------------------------------
/android/libs/com/transistorsoft/tsbackgroundfetch/maven-metadata.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.transistorsoft
4 | tsbackgroundfetch
5 |
6 | 1.0.4
7 | 1.0.4
8 |
9 | 1.0.2
10 | 1.0.3
11 | 1.0.4
12 |
13 | 20241128152535
14 |
15 |
16 |
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # [react-native-background-fetch]
2 | -keep class com.transistorsoft.rnbackgroundfetch.HeadlessTask { *; }
3 |
4 | # for react-native Headless on new architecture
5 | -keep class com.facebook.react.defaults.DefaultNewArchitectureEntryPoint {
6 | public ;
7 | }
8 | -keep class com.facebook.react.ReactApplication {
9 | public ;
10 | }
11 | -keep class com.facebook.react.ReactHost {
12 | public ;
13 | }
14 | -keep class * extends com.facebook.react.ReactHost {
15 | public ;
16 | }
17 | -keep class com.facebook.react.fabric.** { *; }
18 |
19 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/src/main/java/com/transistorsoft/rnbackgroundfetch/HeadlessTask.java:
--------------------------------------------------------------------------------
1 | package com.transistorsoft.rnbackgroundfetch;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.util.Log;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.Nullable;
9 |
10 | import com.facebook.infer.annotation.Assertions;
11 | import com.facebook.react.ReactApplication;
12 | import com.facebook.react.ReactInstanceEventListener;
13 | import com.facebook.react.ReactInstanceManager;
14 | import com.facebook.react.ReactNativeHost;
15 | import com.facebook.react.bridge.ReactContext;
16 | import com.facebook.react.bridge.UiThreadUtil;
17 | import com.facebook.react.bridge.WritableMap;
18 | import com.facebook.react.bridge.WritableNativeMap;
19 | import com.facebook.react.jstasks.HeadlessJsTaskConfig;
20 | import com.facebook.react.jstasks.HeadlessJsTaskContext;
21 |
22 | import com.transistorsoft.tsbackgroundfetch.BGTask;
23 | import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
24 | import com.facebook.react.common.LifecycleState;
25 |
26 | import java.lang.reflect.Method;
27 |
28 | /**
29 | * Created by chris on 2018-01-17.
30 | */
31 |
32 | public class HeadlessTask {
33 | private static final String HEADLESS_TASK_NAME = "BackgroundFetch";
34 | private static final Handler mHandler = new Handler();
35 |
36 | private final BGTask mBGTask;
37 | public HeadlessTask(Context context, BGTask task) {
38 | mBGTask = task;
39 | WritableMap clientEvent = new WritableNativeMap();
40 | clientEvent.putString("taskId", task.getTaskId());
41 | clientEvent.putBoolean("timeout", task.getTimedOut());
42 | HeadlessJsTaskConfig config = new HeadlessJsTaskConfig(HEADLESS_TASK_NAME, clientEvent, 30000);
43 | try {
44 | startTask(config, context);
45 | } catch (AssertionError e) {
46 | Log.d(BackgroundFetch.TAG, "[HeadlessTask] Failed invoke HeadlessTask: " + e.getMessage());
47 | }
48 | }
49 |
50 | /**
51 | * Start a task. This method handles starting a new React instance if required.
52 | *
53 | * Has to be called on the UI thread.
54 | *
55 | * @param taskConfig describes what task to start and the parameters to pass to it
56 | */
57 | protected void startTask(final HeadlessJsTaskConfig taskConfig, Context context) {
58 | UiThreadUtil.assertOnUiThread();
59 |
60 | ReactContext reactContext = getReactContext(context);
61 |
62 | if (reactContext == null) {
63 | createReactContextAndScheduleTask(taskConfig, context);
64 | } else {
65 | invokeStartTask(reactContext, taskConfig);
66 | }
67 | }
68 |
69 | private void invokeStartTask(ReactContext reactContext, final HeadlessJsTaskConfig taskConfig) {
70 | if (reactContext.getLifecycleState() == LifecycleState.RESUMED) {
71 | return;
72 | }
73 | final HeadlessJsTaskContext headlessJsTaskContext = HeadlessJsTaskContext.getInstance(reactContext);
74 |
75 | UiThreadUtil.runOnUiThread(() -> {
76 | try {
77 | final int taskId = headlessJsTaskContext.startTask(taskConfig);
78 | Log.d(BackgroundFetch.TAG, "[HeadlessTask] start taskId: " + taskId);
79 | // Add a BGTask.finish(taskId) listener. This is executed when the user runs BackgroundFetch.finish(taskId).
80 | // We use this to finish the RN headless task.
81 | mBGTask.setCompletionHandler(() -> {
82 | Log.d(BackgroundFetch.TAG, "[HeadlessTask] end taskId: " + taskId);
83 | if (headlessJsTaskContext.isTaskRunning(taskId)) {
84 | headlessJsTaskContext.finishTask(taskId);
85 | }
86 | });
87 | } catch (IllegalStateException exception) {
88 | Log.e(BackgroundFetch.TAG, "[HeadlessTask] task attempted to run in the foreground. Task ignored.");
89 | }
90 | });
91 | }
92 |
93 | private ReactNativeHost getReactNativeHost(Context context) {
94 | return ((ReactApplication) context.getApplicationContext()).getReactNativeHost();
95 | }
96 |
97 | /**
98 | * Get the {ReactHost} used by this app. ure and returns null if not.
99 | */
100 | private @Nullable Object getReactHost(Context context) {
101 | context = context.getApplicationContext();
102 | try {
103 | Method getReactHost = context.getClass().getMethod("getReactHost");
104 | return getReactHost.invoke(context);
105 | // Original non-reflection return:
106 | //return ((ReactApplication) context.getApplicationContext()).getReactHost();
107 | } catch (Exception e) {
108 | Log.d(BackgroundFetch.TAG, "[HeadlessTask] Reflection error ReactHost: " + e);
109 | return null;
110 | }
111 | }
112 |
113 | private ReactContext getReactContext(Context context) {
114 | if (isBridglessArchitectureEnabled()) {
115 | Object reactHost = getReactHost(context);
116 | Assertions.assertNotNull(reactHost, "getReactHost() is null in New Architecture");
117 | try {
118 | Method getCurrentReactContext = reactHost.getClass().getMethod("getCurrentReactContext");
119 | return (ReactContext) getCurrentReactContext.invoke(reactHost);
120 | } catch (Exception e) {
121 | Log.e(BackgroundFetch.TAG, "[HeadlessTask] Reflection error getCurrentReactContext: " + e);
122 | }
123 | }
124 | final ReactInstanceManager reactInstanceManager = getReactNativeHost(context).getReactInstanceManager();
125 | return reactInstanceManager.getCurrentReactContext();
126 | }
127 |
128 | private void createReactContextAndScheduleTask(final HeadlessJsTaskConfig taskConfig, Context context) {
129 | Log.d(BackgroundFetch.TAG, "[HeadlessTask] initializing ReactContext");
130 |
131 | if (isBridglessArchitectureEnabled()) { // new arch
132 | final Object reactHost = getReactHost(context);
133 |
134 | ReactInstanceEventListener callback = new ReactInstanceEventListener() {
135 | @Override
136 | public void onReactContextInitialized(@NonNull ReactContext reactContext) {
137 | mHandler.postDelayed(() -> invokeStartTask(reactContext, taskConfig), 500);
138 | try {
139 | Method removeReactInstanceEventListener = reactHost.getClass().getMethod("removeReactInstanceEventListener", ReactInstanceEventListener.class);
140 | removeReactInstanceEventListener.invoke(reactHost, this);
141 | } catch (Exception e) {
142 | Log.e(BackgroundFetch.TAG, "[HeadlessTask] reflection error removeReactInstanceEventListener" + e);
143 | }
144 | }
145 | };
146 |
147 | try {
148 | Method addReactInstanceEventListener = reactHost.getClass().getMethod("addReactInstanceEventListener", ReactInstanceEventListener.class);
149 | addReactInstanceEventListener.invoke(reactHost, callback);
150 | Method startReactHost = reactHost.getClass().getMethod("start");
151 | startReactHost.invoke(reactHost);
152 | } catch (Exception e) {
153 | Log.e(BackgroundFetch.TAG, "[HeadlessTask] reflection error addReactInstanceEventListener: " + e);
154 | }
155 | } else { // old arch
156 | final ReactInstanceManager reactInstanceManager = getReactNativeHost(context).getReactInstanceManager();
157 | reactInstanceManager.addReactInstanceEventListener(new ReactInstanceEventListener() {
158 | @Override
159 | public void onReactContextInitialized(@NonNull ReactContext reactContext) {
160 | mHandler.postDelayed(() -> invokeStartTask(reactContext, taskConfig), 500);
161 | reactInstanceManager.removeReactInstanceEventListener(this);
162 | }
163 | });
164 | reactInstanceManager.createReactContextInBackground();
165 | }
166 | }
167 |
168 | // Returns true if the app has enabled bridgeless mode. Thanks to @mikehardy for this block.
169 | private boolean isBridglessArchitectureEnabled() {
170 | try {
171 | Class> entryPoint = Class.forName("com.facebook.react.defaults.DefaultNewArchitectureEntryPoint");
172 | Method bridgelessEnabled = entryPoint.getMethod("getBridgelessEnabled");
173 | Object result = bridgelessEnabled.invoke(null);
174 | return (result == Boolean.TRUE);
175 | } catch (Exception e) {
176 | return false;
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/android/src/main/java/com/transistorsoft/rnbackgroundfetch/RNBackgroundFetchModule.java:
--------------------------------------------------------------------------------
1 | package com.transistorsoft.rnbackgroundfetch;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.util.Log;
6 |
7 | import com.facebook.react.bridge.*;
8 | import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
9 | import com.transistorsoft.tsbackgroundfetch.BackgroundFetch;
10 | import com.transistorsoft.tsbackgroundfetch.BackgroundFetchConfig;
11 | import com.transistorsoft.tsbackgroundfetch.LifecycleManager;
12 |
13 | public class RNBackgroundFetchModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
14 | public static final String TAG = "RNBackgroundFetch";
15 | private static final String EVENT_FETCH = "fetch";
16 | private static final String JOB_SERVICE_CLASS = HeadlessTask.class.getName();
17 | private static final String FETCH_TASK_ID = "react-native-background-fetch";
18 | private boolean initialized = false;
19 |
20 | public RNBackgroundFetchModule(ReactApplicationContext reactContext) {
21 | super(reactContext);
22 | Log.d(BackgroundFetch.TAG, "[RNBackgroundFetch initialize]");
23 | BackgroundFetch.getInstance(reactContext.getApplicationContext());
24 | reactContext.addLifecycleEventListener(this);
25 | }
26 |
27 | @Override
28 | public String getName() {
29 | return TAG;
30 | }
31 |
32 | @ReactMethod
33 | public void configure(ReadableMap options, final Callback success, final Callback failure) {
34 | BackgroundFetch adapter = getAdapter();
35 |
36 | BackgroundFetch.Callback callback = new BackgroundFetch.Callback() {
37 | @Override public void onFetch(String taskId) {
38 | WritableMap params = new WritableNativeMap();
39 | params.putString("taskId", taskId);
40 | params.putBoolean("timeout", false);
41 | getReactApplicationContext().getJSModule(RCTNativeAppEventEmitter.class).emit(EVENT_FETCH, params);
42 | }
43 | @Override public void onTimeout(String taskId) {
44 | WritableMap params = new WritableNativeMap();
45 | params.putString("taskId", taskId);
46 | params.putBoolean("timeout", true);
47 | getReactApplicationContext().getJSModule(RCTNativeAppEventEmitter.class).emit(EVENT_FETCH, params);
48 | }
49 | };
50 | adapter.configure(buildConfig(options)
51 | .setTaskId(FETCH_TASK_ID)
52 | .setIsFetchTask(true)
53 | .build(), callback);
54 |
55 | success.invoke(BackgroundFetch.STATUS_AVAILABLE);
56 | }
57 |
58 | @ReactMethod
59 | public void scheduleTask(ReadableMap options, final Callback success, final Callback failure) {
60 | BackgroundFetch adapter = getAdapter();
61 | adapter.scheduleTask(buildConfig(options).build());
62 | success.invoke(true);
63 | }
64 |
65 | @ReactMethod
66 | public void start(Callback success, Callback failure) {
67 | BackgroundFetch adapter = getAdapter();
68 | adapter.start(FETCH_TASK_ID);
69 | success.invoke(adapter.status());
70 | }
71 |
72 | @ReactMethod
73 | public void stop(String taskId, Callback success, Callback failure) {
74 | if (taskId == null) taskId = FETCH_TASK_ID;
75 | BackgroundFetch adapter = getAdapter();
76 | adapter.stop(taskId);
77 | success.invoke(true);
78 | }
79 |
80 | @ReactMethod
81 | public void status(Callback success) {
82 | BackgroundFetch adapter = getAdapter();
83 | success.invoke(adapter.status());
84 | }
85 |
86 | @ReactMethod
87 | public void finish(String taskId) {
88 | BackgroundFetch adapter = getAdapter();
89 | adapter.finish(taskId);
90 | }
91 |
92 | @ReactMethod
93 | public void addListener(String event) {
94 | // Keep: Required for RN built-in NativeEventEmitter calls.
95 | }
96 |
97 | @ReactMethod
98 | public void removeListeners(Integer count) {
99 | // Keep: Required for RN built-in NativeEventEmitter calls.
100 | }
101 |
102 | @Override
103 | public void onHostResume() {
104 | if (!initialized) {
105 | initializeBackgroundFetch();
106 | }
107 | }
108 |
109 | @Override
110 | public void onHostPause() {
111 | }
112 |
113 | @Override
114 | public void onNewIntent(Intent intent) {
115 | }
116 |
117 | @Override
118 | public void onHostDestroy() {
119 | LifecycleManager.getInstance().setHeadless(true);
120 | initialized = false;
121 | }
122 |
123 | @Override
124 | public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
125 |
126 | }
127 |
128 | private BackgroundFetchConfig.Builder buildConfig(ReadableMap options) {
129 | BackgroundFetchConfig.Builder config = new BackgroundFetchConfig.Builder();
130 | if (options.hasKey(BackgroundFetchConfig.FIELD_MINIMUM_FETCH_INTERVAL)) {
131 | config.setMinimumFetchInterval(options.getInt(BackgroundFetchConfig.FIELD_MINIMUM_FETCH_INTERVAL));
132 | }
133 | if (options.hasKey(BackgroundFetchConfig.FIELD_TASK_ID)) {
134 | config.setTaskId(options.getString(BackgroundFetchConfig.FIELD_TASK_ID));
135 | }
136 | if (options.hasKey(BackgroundFetchConfig.FIELD_DELAY)) {
137 | Integer delay = options.getInt(BackgroundFetchConfig.FIELD_DELAY);
138 | config.setDelay(delay.longValue());
139 | }
140 | if (options.hasKey(BackgroundFetchConfig.FIELD_STOP_ON_TERMINATE)) {
141 | config.setStopOnTerminate(options.getBoolean(BackgroundFetchConfig.FIELD_STOP_ON_TERMINATE));
142 | }
143 | if (options.hasKey(BackgroundFetchConfig.FIELD_FORCE_ALARM_MANAGER)) {
144 | config.setForceAlarmManager(options.getBoolean(BackgroundFetchConfig.FIELD_FORCE_ALARM_MANAGER));
145 | }
146 | if (options.hasKey(BackgroundFetchConfig.FIELD_START_ON_BOOT)) {
147 | config.setStartOnBoot(options.getBoolean(BackgroundFetchConfig.FIELD_START_ON_BOOT));
148 | }
149 | if (options.hasKey("enableHeadless") && options.getBoolean("enableHeadless")) {
150 | config.setJobService(JOB_SERVICE_CLASS);
151 | }
152 | if (options.hasKey(BackgroundFetchConfig.FIELD_REQUIRED_NETWORK_TYPE)) {
153 | config.setRequiredNetworkType(options.getInt(BackgroundFetchConfig.FIELD_REQUIRED_NETWORK_TYPE));
154 | }
155 | if (options.hasKey(BackgroundFetchConfig.FIELD_REQUIRES_BATTERY_NOT_LOW)) {
156 | config.setRequiresBatteryNotLow(options.getBoolean(BackgroundFetchConfig.FIELD_REQUIRES_BATTERY_NOT_LOW));
157 | }
158 | if (options.hasKey(BackgroundFetchConfig.FIELD_REQUIRES_CHARGING)) {
159 | config.setRequiresCharging(options.getBoolean(BackgroundFetchConfig.FIELD_REQUIRES_CHARGING));
160 | }
161 | if (options.hasKey(BackgroundFetchConfig.FIELD_REQUIRES_DEVICE_IDLE)) {
162 | config.setRequiresDeviceIdle(options.getBoolean(BackgroundFetchConfig.FIELD_REQUIRES_DEVICE_IDLE));
163 | }
164 | if (options.hasKey(BackgroundFetchConfig.FIELD_REQUIRES_STORAGE_NOT_LOW)) {
165 | config.setRequiresStorageNotLow(options.getBoolean(BackgroundFetchConfig.FIELD_REQUIRES_STORAGE_NOT_LOW));
166 | }
167 | if (options.hasKey(BackgroundFetchConfig.FIELD_PERIODIC)) {
168 | config.setPeriodic(options.getBoolean(BackgroundFetchConfig.FIELD_PERIODIC));
169 | }
170 | return config;
171 | }
172 |
173 | private void initializeBackgroundFetch() {
174 | Activity activity = getCurrentActivity();
175 | if (activity == null) {
176 | return;
177 | }
178 | initialized = true;
179 | }
180 |
181 | private BackgroundFetch getAdapter() {
182 | return BackgroundFetch.getInstance(getReactApplicationContext());
183 | }
184 |
185 | }
186 |
--------------------------------------------------------------------------------
/android/src/main/java/com/transistorsoft/rnbackgroundfetch/RNBackgroundFetchPackage.java:
--------------------------------------------------------------------------------
1 | package com.transistorsoft.rnbackgroundfetch;
2 |
3 | import com.facebook.react.ReactPackage;
4 | import com.facebook.react.bridge.JavaScriptModule;
5 | import com.facebook.react.bridge.NativeModule;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.react.uimanager.ViewManager;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Collections;
11 | import java.util.List;
12 |
13 | public class RNBackgroundFetchPackage implements ReactPackage {
14 | @Override
15 | public List createNativeModules (ReactApplicationContext reactContext) {
16 | List modules = new ArrayList<>();
17 | modules.add(new RNBackgroundFetchModule(reactContext));
18 | return modules;
19 | }
20 |
21 | public List> createJSModules() {
22 | return Collections.emptyList();
23 | }
24 |
25 | @Override
26 | public List createViewManagers(ReactApplicationContext reactContext) {
27 | return Collections.emptyList();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app.plugin.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./expo/plugin/build');
2 |
--------------------------------------------------------------------------------
/docs/INSTALL-AUTO-ANDROID.md:
--------------------------------------------------------------------------------
1 | # Android Auto-linking Setup
2 |
3 | ### `react-native >= 0.60`
4 |
5 | ### With `yarn`
6 |
7 | ```bash
8 | $ yarn add react-native-background-fetch
9 | ```
10 |
11 | ### With `npm`
12 | ```bash
13 | $ npm install --save react-native-background-fetch
14 | ```
15 |
16 | ## Gradle Configuration
17 |
18 | The SDK requires a custom __`maven url`__ in the root __`android/build.gradle`__.
19 | Please note that some more recent versions of React Native the Android template may not include __`allprojects`__ section. You should add this manually as a separate section along with the nested __`repositories`__ section in the same __`android/build.gradle`__ file.
20 |
21 | ### :open_file_folder: **`android/build.gradle`**
22 |
23 | ```diff
24 | allprojects {
25 | repositories {
26 | mavenLocal()
27 | maven {
28 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
29 | url("$rootDir/../node_modules/react-native/android")
30 | }
31 | maven {
32 | // Android JSC is installed from npm
33 | url("$rootDir/../node_modules/jsc-android/dist")
34 | }
35 | + maven {
36 | + // react-native-background-fetch
37 | + url("${project(':react-native-background-fetch').projectDir}/libs")
38 | + }
39 |
40 | }
41 | }
42 | ```
43 |
44 | ## Precise event-scheduling with `forceAlarmManager: true`:
45 |
46 | **Only** If you wish to use precise scheduling of events with __`forceAlarmManager: true`__, *Android 14 (SDK 34)*, has restricted usage of ["`AlarmManager` exact alarms"](https://developer.android.com/about/versions/14/changes/schedule-exact-alarms). To continue using precise timing of events with *Android 14*, you can manually add this permission to your __`AndroidManifest`__. Otherwise, the plugin will gracefully fall-back to "*in-exact* `AlarmManager` scheduling":
47 |
48 | :open_file_folder: In your `AndroidManifest`, add the following permission (**exactly as-shown**):
49 |
50 | ```xml
51 |
52 |
53 | .
54 | .
55 | .
56 |
57 | ```
58 | :warning: It has been announced that *Google Play Store* [has plans to impose greater scrutiny](https://support.google.com/googleplay/android-developer/answer/13161072?sjid=3640341614632608469-NA) over usage of this permission (which is why the plugin does not automatically add it).
59 |
60 |
--------------------------------------------------------------------------------
/docs/INSTALL-AUTO-IOS.md:
--------------------------------------------------------------------------------
1 | # iOS Auto-linking Setup
2 | ### `react-native >= 0.60`
3 |
4 | ### With `yarn`
5 |
6 | ```bash
7 | $ yarn add react-native-background-fetch
8 | ```
9 |
10 | ### With `npm`
11 | ```bash
12 | $ npm install --save react-native-background-fetch
13 | ```
14 |
15 | ## `pod install`
16 |
17 | **:warning: requires *cocoapods* `>= 1.10+`:**
18 |
19 | ```bash
20 | $ pod --version
21 | // if < 1.10.0
22 | $ sudo gem install cocoapods
23 | ```
24 |
25 | ```bash
26 | $ cd ios
27 | $ pod install
28 | ```
29 |
30 | ## Configure Background Capabilities
31 |
32 | - Select the root of your project. Select **Capabilities** tab. Enable **Background Modes** and enable the following mode:
33 |
34 | - [x] Background fetch
35 | - [x] Background processing (:new: __iOS 13+__; Only if you intend to use `BackgroundFetch.scheduleTask`)
36 |
37 | 
38 |
39 |
40 | ## Configure `Info.plist` (:new: __iOS 13+__)
41 | 1. Open your `Info.plist` and add the key *"Permitted background task scheduler identifiers"*
42 |
43 | 
44 |
45 | 2. Add the **required identifier `com.transistorsoft.fetch`**.
46 |
47 | 
48 |
49 | 3. If you intend to execute your own custom tasks via **`BackgroundFetch.scheduleTask`**, you must add those custom identifiers as well. For example, if you intend to execute a custom **`taskId: 'com.transistorsoft.customtask'`**, you must add the identifier **`com.transistorsoft.customtask`** to your *"Permitted background task scheduler identifiers"*, as well.
50 |
51 | :warning: A task identifier can be any string you wish, but it's a good idea to prefix them now with `com.transistorsoft.` — In the future, the `com.transistorsoft` prefix **may become required**.
52 |
53 | ```javascript
54 | BackgroundFetch.scheduleTask({
55 | taskId: 'com.transistorsoft.customtask',
56 | delay: 60 * 60 * 1000 // In one hour (milliseconds)
57 | });
58 | ```
59 |
60 | ## Privacy Manifest
61 |
62 | Apple now requires apps provide a [Privacy Manifest for "sensitive" APIs](https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api?language=objc) which could be abused for "fingerprinting" a user for malicious marketing activity.
63 |
64 | If your app does not yet have a *Privacy Manifest* (__`PrivacyInfo.xcprivacy`__), create one now:
65 |
66 |
67 | ℹ️ Click here for detailed instructions...
68 |
69 | - In XCode, __`File -> New -> File...`__:
70 |
71 | 
72 |
73 | - Be sure to enable your `Targets: [x] YourApp`:
74 |
75 | 
76 |
77 |
78 |
79 |
80 |
81 | It's best to edit this file's XML manually.
82 | - :open_file_folder: `ios/PrivacyInfo.xcprivacy`
83 | - Add the following block within the `NSPrivacyAccessedAPITypes` `` container:
84 |
85 | ```xml
86 |
87 |
88 |
89 |
90 |
91 | NSPrivacyAccessedAPITypes
92 |
93 |
94 |
95 | NSPrivacyAccessedAPIType
96 | NSPrivacyAccessedAPICategoryUserDefaults
97 |
98 | NSPrivacyAccessedAPITypeReasons
99 |
100 | CA92.1
101 |
102 |
103 |
104 |
105 |
106 | ```
107 |
108 | ## `AppDelegate`
109 | :open_file_folder: __`AppDelegate.m`__
110 |
111 | ```diff
112 | #import "AppDelegate.h"
113 |
114 | #import
115 | #import
116 | #import
117 |
118 | // IMPORTANT: Paste import ABOVE the DEBUG macro
119 | +#import
120 |
121 | #if DEBUG
122 | .
123 | . ///////////////////////////////////////////////////////////////////////////////////
124 | . // IMPORTANT: DO NOT paste import within DEBUG macro or archiving will fail!!!
125 | . ///////////////////////////////////////////////////////////////////////////////////
126 | .
127 | #endif
128 |
129 | @implementation AppDelegate
130 |
131 | (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
132 | .
133 | .
134 | .
135 | + // [REQUIRED] Register BackgroundFetch
136 | + [[TSBackgroundFetch sharedInstance] didFinishLaunching];
137 |
138 | return YES;
139 | }
140 | ```
141 |
142 | #### Or if you're using `Swift`:
143 | :open_file_folder: __`AppDelegate.swift`__:
144 |
145 | ```diff
146 | import Foundation
147 | import UIKit
148 | +import TSBackgroundFetch
149 |
150 | @UIApplicationMain
151 | class AppDelegate: RCTAppDelegate {
152 |
153 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
154 | .
155 | .
156 | .
157 | + // [REQUIRED] Register BackgroundFetch
158 | + TSBackgroundFetch.sharedInstance().didFinishLaunching();
159 | return self.application(application, didFinishLaunchingWithOptions: launchOptions);
160 | }
161 | }
162 | ```
163 |
164 | ## BackgroundFetch AppDelegate extension
165 |
166 | :warning: Deprecated iOS Background Fetch API for devices running __`< iOS 13`__.
167 |
168 | BackgroundFetch implements an `AppDelegate` method `didPerformFetchWithCompletionHandler`. You must manually add this file to the same folder where your `AppDelegate.m` lives:
169 |
170 | - In the XCode's **`Project navigator`**, right click on project's name ➜ **`Add Files to <...>`**.
171 | - **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch/RNBackgroundFetch+AppDelegate.m`**.
172 |
173 | 
174 |
175 | **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch/RNBackgroundFetch+AppDelegate.m`**
176 | 
177 |
178 |
179 |
--------------------------------------------------------------------------------
/docs/INSTALL-COCOAPODS-IOS.md:
--------------------------------------------------------------------------------
1 | # iOS Installation with CocoaPods
2 |
3 | ## With `yarn`
4 |
5 | ```bash
6 | $ yarn add react-native-background-fetch
7 | ```
8 |
9 | ## With `npm`
10 | ```bash
11 | $ npm install --save react-native-background-fetch
12 | ```
13 |
14 | ### `Podfile`
15 |
16 | If you **don't** already have an `ios/Podfile` initialized, run the following command:
17 | ```shell
18 | $ cd ios
19 | $ pod init
20 | ```
21 |
22 | Replace the contents of `Podfile` with the following, substituting `_YOUR_PROJECT_TARGET`:
23 | ```ruby
24 | # Uncomment the next line to define a global platform for your project
25 | # platform :ios, '9.0'
26 |
27 | target '_YOUR_PROJECT_TARGET_' do
28 | rn_path = '../node_modules/react-native'
29 |
30 | # See http://facebook.github.io/react-native/docs/integration-with-existing-apps.html#configuring-cocoapods-dependencies
31 | pod 'yoga', path: "#{rn_path}/ReactCommon/yoga/yoga.podspec"
32 | pod 'React', path: rn_path, subspecs: [
33 | 'Core',
34 | 'CxxBridge',
35 | 'DevSupport',
36 | 'RCTActionSheet',
37 | 'RCTAnimation',
38 | 'RCTGeolocation',
39 | 'RCTImage',
40 | 'RCTLinkingIOS',
41 | 'RCTNetwork',
42 | 'RCTSettings',
43 | 'RCTText',
44 | 'RCTVibration',
45 | 'RCTWebSocket',
46 | ]
47 |
48 | # React Native third party dependencies podspecs
49 | pod 'DoubleConversion', :podspec => "#{rn_path}/third-party-podspecs/DoubleConversion.podspec"
50 | pod 'glog', :podspec => "#{rn_path}/third-party-podspecs/glog.podspec"
51 | # If you are using React Native <0.54, you will get the following error:
52 | # "The name of the given podspec `GLog` doesn't match the expected one `glog`"
53 | # Use the following line instead:
54 | #pod 'GLog', :podspec => "#{rn_path}/third-party-podspecs/GLog.podspec"
55 | pod 'Folly', :podspec => "#{rn_path}/third-party-podspecs/Folly.podspec"
56 |
57 | end
58 |
59 | post_install do |installer|
60 | installer.pods_project.targets.each do |target|
61 | if target.name == "React"
62 | target.remove_from_project
63 | end
64 | end
65 | end
66 |
67 | ```
68 |
69 | ### `react-native link`
70 |
71 | Running `react-native link` will automatically install the plugin into your `Podfile`.
72 |
73 | - Follow the [`react-native link` instructions](./INSTALL-LINK-IOS.md).
74 | - Install the new CocoaPods:
75 |
76 | ```shell
77 | $ cd ios
78 | $ pod install
79 | ```
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/docs/INSTALL-EXPO.md:
--------------------------------------------------------------------------------
1 | # Expo Setup
2 |
3 | ```bash
4 | npx expo install react-native-background-fetch
5 | ```
6 |
7 | ### :open_file_folder: **`app.json`**
8 |
9 | - Add the following to __`plugins`__:
10 |
11 | ```diff
12 | {
13 | "expo": {
14 | "name": "your-app-name",
15 | "plugins": [
16 | + "react-native-background-fetch"
17 | ]
18 | }
19 | }
20 | ```
21 |
22 | - Add the following __`UIBackgroundModes`__ and __`BGTaskSchedulerPermittedIdentifiers`__ to the __`ios.infoPlist`__ section:
23 |
24 |
25 | ```diff
26 | {
27 | "expo": {
28 | "name": "your-app-name",
29 | "plugins": [
30 | "react-native-background-fetch"
31 | ],
32 | "ios": {
33 | + "infoPlist": {
34 | + "UIBackgroundModes": [
35 | + "fetch",
36 | + "processing"
37 | + ],
38 | + "BGTaskSchedulerPermittedIdentifiers": [
39 | + "com.transistorsoft.fetch"
40 | + ]
41 | + }
42 | }
43 | }
44 | }
45 | ```
46 |
47 | - If you intend to execute your own custom tasks via **`BackgroundFetch.scheduleTask`**, you must add those custom identifiers as well to the __`BGTaskSchedulerPermittedIdentifiers`__. For example, if you intend to execute a custom **`taskId: 'com.transistorsoft.customtask'`**, you must add the identifier **`com.transistorsoft.customtask`** to `BGTaskSchedulerPermittedIdentifiers`:
48 |
49 | ```diff
50 | "BGTaskSchedulerPermittedIdentifiers": [
51 | "com.transistorsoft.fetch",
52 | + "com.transistorsoft.customtask"
53 | ]
54 | ```
55 |
56 | :warning: A task identifier can be any string you wish, but it's a good idea to prefix them now with `com.transistorsoft.` — In the future, the `com.transistorsoft` prefix **may become required**.
57 |
58 | ```javascript
59 | BackgroundFetch.scheduleTask({
60 | taskId: 'com.transistorsoft.customtask',
61 | delay: 60 * 60 * 1000 // In one hour (milliseconds)
62 | });
63 | ```
64 |
65 | ### Re-build
66 |
67 | You must rebuild your Android app for the added plugins to be evaluated.
68 |
69 | - If you're developing locally:
70 |
71 | ```bash
72 | npx expo prebuild
73 | ```
74 |
75 | - If you're using *Expo EAS*:
76 | ```bash
77 | eas build --profile development --platform android
78 | ```
79 |
80 |
81 |
--------------------------------------------------------------------------------
/docs/INSTALL-LINK-ANDROID.md:
--------------------------------------------------------------------------------
1 | # Android `react-native link` Installation
2 |
3 | No manual steps required.
4 |
5 | ### With `yarn`
6 |
7 | ```bash
8 | $ yarn add react-native-background-fetch
9 | ```
10 |
11 | ### With `npm`
12 | ```bash
13 | $ npm install --save react-native-background-fetch
14 | ```
15 |
16 | ### `react-native link`
17 | ```bash
18 | $ react-native link react-native-background-fetch
19 | ```
20 |
--------------------------------------------------------------------------------
/docs/INSTALL-LINK-IOS.md:
--------------------------------------------------------------------------------
1 | # iOS Installation with `react-native link`
2 |
3 | ### With `yarn`
4 |
5 | ```bash
6 | $ yarn add react-native-background-fetch
7 | ```
8 |
9 | ### With `npm`
10 | ```bash
11 | $ npm install --save react-native-background-fetch
12 | ```
13 |
14 | ### `react-native link`
15 |
16 | ```bash
17 | $ react-native link react-native-background-fetch
18 | ```
19 |
20 | ### `pod install`
21 |
22 | ```bash
23 | $ cd ios
24 | $ pod install
25 | ```
26 |
27 | ## Configure Background Capabilities
28 |
29 | - Select the root of your project. Select **Capabilities** tab. Enable **Background Modes** and enable the following mode:
30 |
31 | - [x] Background fetch
32 | - [x] Background processing (:new: __iOS 13+__; Only if you intend to use `BackgroundFetch.scheduleTask`)
33 |
34 | 
35 |
36 |
37 | ## Configure `Info.plist` (:new: __iOS 13+__)
38 | 1. Open your `Info.plist` and the key *"Permitted background task scheduler identifiers"*
39 |
40 | 
41 |
42 | 2. Add the **required identifier `com.transistorsoft.fetch`**.
43 |
44 | 
45 |
46 | 3. If you intend to execute your own custom tasks via **`BackgroundFetch.scheduleTask`**, you must add those custom identifiers as well. For example, if you intend to execute a custom **`taskId: 'com.foo.customtask'`**, you must add the identifier **`com.foo.customtask`** to your *"Permitted background task scheduler identifiers"*, as well.
47 |
48 | ```dart
49 | BackgroundFetch.scheduleTask({
50 | taskId: 'com.foo.customtask',
51 | delay: 60 * 60 * 1000 // In one hour (milliseconds)
52 | });
53 | ```
54 |
55 | ## `AppDelegate.m` (:new: __iOS 13+__)
56 |
57 | The [**`BGTaskScheduler`**](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler?language=objc) API introduced in iOS 13 requires special setup:
58 |
59 | ```diff
60 | +#import
61 |
62 | @implementation AppDelegate
63 |
64 | (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
65 | .
66 | .
67 | .
68 | + // [REQUIRED] Register BackgroundFetch
69 | + [[TSBackgroundFetch sharedInstance] didFinishLaunching];
70 |
71 | return YES;
72 | }
73 | ```
74 |
75 | ## BackgroundFetch AppDelegate extension
76 |
77 | :warning: Deprecated iOS Background Fetch API for devices running __`< iOS 13`__.
78 |
79 | BackgroundFetch implements an `AppDelegate` method `didPerformFetchWithCompletionHandler`. You must manually add this file to the same folder where your `AppDelegate.m` lives:
80 |
81 | - In the XCode's **`Project navigator`**, right click on project's name ➜ **`Add Files to <...>`**.
82 | - **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch/RNBackgroundFetch+AppDelegate.m`**.
83 |
84 | 
85 |
86 | **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch/RNBackgroundFetch+AppDelegate.m`**
87 | 
88 |
--------------------------------------------------------------------------------
/docs/INSTALL-MANUAL-ANDROID.md:
--------------------------------------------------------------------------------
1 | # Android Manual Installation
2 |
3 | ## With `yarn`
4 |
5 | ```bash
6 | $ yarn add react-native-background-fetch
7 | ```
8 |
9 | ## With `npm`
10 |
11 | ```bash
12 | $ npm install --save react-native-background-fetch
13 | ```
14 |
15 | ## Gradle Configuration
16 |
17 | ### :open_file_folder: **`android/settings.gradle`**
18 |
19 | ```diff
20 | +include ':react-native-background-fetch'
21 | +project(':react-native-background-fetch').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-background-fetch/android')
22 | ```
23 |
24 | -------------------------------------------------------------------------------
25 |
26 |
27 | ### :open_file_folder: **`android/app/build.gradle`**
28 |
29 | ```diff
30 | dependencies {
31 | + implementation project(':react-native-background-fetch')
32 | }
33 | ```
34 |
35 |
36 | ## MainApplication.java
37 |
38 | ### :open_file_folder: **`android/app/main/java/com/.../MainApplication.java`**
39 |
40 | ```diff
41 | +import com.transistorsoft.rnbackgroundfetch.RNBackgroundFetchPackage;
42 | public class MainApplication extends ReactApplication {
43 | @Override
44 | protected List getPackages() {
45 | return Arrays.asList(
46 | + new RNBackgroundFetchPackage(),
47 | new MainReactPackage()
48 | );
49 | }
50 | }
51 | ```
52 |
--------------------------------------------------------------------------------
/docs/INSTALL-MANUAL-IOS.md:
--------------------------------------------------------------------------------
1 | # iOS Manual Installation
2 |
3 | - `npm install react-native-background-fetch --save`
4 |
5 | - In the XCode's **`Project navigator`**, right click on project's name ➜ **`Add Files to <...>`**
6 | 
7 |
8 | - Add **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch.xcodeproj`**
9 | 
10 |
11 | ## Build Phases ➜ Link Binary With Libraries
12 |
13 | - Select your project in the **`Project navigator`**. Click **`Build Phases`** then **`Link Binary With Libraries`**. Add the following static library:
14 | - **`libRNBackgroundFetch.a`**.
15 | 
16 |
17 | - BackgroundGeolocation includes custom iOS framework. This needs to be added manually, unfortunately.
18 | - Click **`[Add Other...]`**.
19 | - Navigate: **`node_modules/react-native-background-fetch/ios/RNBackgroundFetch`**.
20 | - Add **`TSBackgroundFetch.framework`**.
21 | 
22 |
23 | ## Build Settings ➜ Framework Search Paths
24 |
25 | - In order to the find the **`TSBackgroundFetch.framework`** you just added, you have to tell Xcode where it can find it:
26 | - Go to **Build Settings** and search for **"framework search path"**.
27 | - Add the following paths (select **recursive [v]**):
28 |
29 | ```
30 | $(PROJECT_DIR)/../node_modules/react-native-background-fetch/ios
31 | ```
32 |
33 | 
34 |
35 | ## Configure Background Capabilities
36 |
37 | - Select the root of your project. Select **Capabilities** tab. Enable **Background Modes** and enable the following mode:
38 |
39 | - [x] Background fetch
40 |
41 | 
42 |
43 | ## BackgroundFetch AppDelegate extension
44 |
45 | BackgroundFetch implements an `AppDelegate` method `didPerformFetchWithCompletionHandler`. You must manually add this file to the same folder where your `AppDelegate.m` lives:
46 |
47 | - Expand the **`RNBackgroundFetch`** project and drag/drop the file **`RNBackgroundFetch+AppDelegate.m`** and place the file to exist **in the same folder** as your app's **`AppDelegate.m`**.
48 | 
49 |
50 | You can now [import and build](../README.md#example)
51 |
--------------------------------------------------------------------------------
/example/.buckconfig:
--------------------------------------------------------------------------------
1 |
2 | [android]
3 | target = Google Inc.:Google APIs:23
4 |
5 | [maven_repositories]
6 | central = https://repo1.maven.org/maven2
7 |
--------------------------------------------------------------------------------
/example/.editorconfig:
--------------------------------------------------------------------------------
1 | # Windows files
2 | [*.bat]
3 | end_of_line = crlf
4 |
--------------------------------------------------------------------------------
/example/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: '@react-native-community',
4 | };
5 |
--------------------------------------------------------------------------------
/example/.gitattributes:
--------------------------------------------------------------------------------
1 | # Windows files should use crlf line endings
2 | # https://help.github.com/articles/dealing-with-line-endings/
3 | *.bat text eol=crlf
4 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | #
3 | .DS_Store
4 |
5 | # Xcode
6 | #
7 | build/
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata
17 | *.xccheckout
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 | ios/.xcode.env.local
24 |
25 | # Android/IntelliJ
26 | #
27 | build/
28 | .idea
29 | .gradle
30 | local.properties
31 | *.iml
32 | *.hprof
33 | .cxx/
34 |
35 | # node.js
36 | #
37 | node_modules/
38 | npm-debug.log
39 | yarn-error.log
40 |
41 | # BUCK
42 | buck-out/
43 | \.buckd/
44 | *.keystore
45 | !debug.keystore
46 |
47 | # fastlane
48 | #
49 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
50 | # screenshots whenever they are needed.
51 | # For more information about the recommended setup visit:
52 | # https://docs.fastlane.tools/best-practices/source-control/
53 |
54 | */fastlane/report.xml
55 | */fastlane/Preview.html
56 | */fastlane/screenshots
57 | **/fastlane/test_output
58 |
59 | # Bundle artifact
60 | *.jsbundle
61 |
62 | # Ruby / CocoaPods
63 | /ios/Pods/
64 | /vendor/bundle/
65 |
--------------------------------------------------------------------------------
/example/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | bracketSpacing: false,
3 | jsxBracketSameLine: true,
4 | arrowParens: 'avoid',
5 | bracketSameLine: true,
6 | bracketSpacing: false,
7 | singleQuote: true,
8 | trailingComma: 'all',
9 | arrowParens: 'avoid',
10 | };
11 |
--------------------------------------------------------------------------------
/example/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.5
2 |
--------------------------------------------------------------------------------
/example/.watchmanconfig:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/example/App.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * Sample React Native App
3 | * https://github.com/facebook/react-native
4 | *
5 | * Generated with the TypeScript template
6 | * https://github.com/react-native-community/react-native-template-typescript
7 | *
8 | * @format
9 | */
10 |
11 | import React from 'react';
12 | import {
13 | SafeAreaView,
14 | ScrollView,
15 | StatusBar,
16 | StyleSheet,
17 | Text,
18 | View,
19 | Switch,
20 | Button,
21 | Alert
22 | } from 'react-native';
23 |
24 | import BackgroundFetch from "react-native-background-fetch";
25 |
26 | const Colors = {
27 | gold: '#fedd1e',
28 | black: '#000',
29 | white: '#fff',
30 | lightGrey: '#ccc',
31 | blue: '#337AB7',
32 | }
33 |
34 | /// Util class for handling fetch-event peristence in AsyncStorage.
35 | import Event from "./src/Event";
36 |
37 | const App = () => {
38 |
39 | const [enabled, setEnabled] = React.useState(false);
40 | const [status, setStatus] = React.useState(-1);
41 | const [events, setEvents] = React.useState([]);
42 |
43 | React.useEffect(() => {
44 | initBackgroundFetch()
45 | loadEvents();
46 | }, []);
47 |
48 | /// Configure BackgroundFetch.
49 | ///
50 | const initBackgroundFetch = async () => {
51 | const status:number = await BackgroundFetch.configure({
52 | minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
53 | stopOnTerminate: false,
54 | enableHeadless: true,
55 | startOnBoot: true,
56 | // Android options
57 | forceAlarmManager: false, // <-- Set true to bypass JobScheduler.
58 | requiredNetworkType: BackgroundFetch.NETWORK_TYPE_NONE, // Default
59 | requiresCharging: false, // Default
60 | requiresDeviceIdle: false, // Default
61 | requiresBatteryNotLow: false, // Default
62 | requiresStorageNotLow: false, // Default
63 | }, async (taskId:string) => {
64 | console.log('[BackgroundFetch] taskId', taskId);
65 | // Create an Event record.
66 | const event = await Event.create(taskId, false);
67 | // Update state.
68 | setEvents((prev) => [...prev, event]);
69 | // Finish.
70 | BackgroundFetch.finish(taskId);
71 | }, (taskId:string) => {
72 | // Oh No! Our task took too long to complete and the OS has signalled
73 | // that this task must be finished immediately.
74 | console.log('[Fetch] TIMEOUT taskId:', taskId);
75 | BackgroundFetch.finish(taskId);
76 | });
77 | setStatus(status);
78 | setEnabled(true);
79 | }
80 |
81 | /// Load persisted events from AsyncStorage.
82 | ///
83 | const loadEvents = () => {
84 | Event.all().then((data) => {
85 | setEvents(data);
86 | }).catch((error) => {
87 | Alert.alert('Error', 'Failed to load data from AsyncStorage: ' + error);
88 | });
89 | }
90 |
91 | /// Toggle BackgroundFetch ON/OFF
92 | ///
93 | const onClickToggleEnabled = (value:boolean) => {
94 | setEnabled(value);
95 |
96 | if (value) {
97 | BackgroundFetch.start();
98 | } else {
99 | BackgroundFetch.stop();
100 | }
101 | }
102 |
103 | /// [Status] button handler.
104 | ///
105 | const onClickStatus = () => {
106 | BackgroundFetch.status().then((status:number) => {
107 | let statusConst = '';
108 | switch (status) {
109 | case BackgroundFetch.STATUS_AVAILABLE:
110 | statusConst = 'STATUS_AVAILABLE';
111 | break;
112 | case BackgroundFetch.STATUS_DENIED:
113 | statusConst = 'STATUS_DENIED';
114 | break;
115 | case BackgroundFetch.STATUS_RESTRICTED:
116 | statusConst = 'STATUS_RESTRICTED';
117 | break;
118 | }
119 | Alert.alert('BackgroundFetch.status()', `${statusConst} (${status})`);
120 | });
121 | }
122 |
123 | /// [scheduleTask] button handler.
124 | /// Schedules a custom-task to fire in 5000ms
125 | ///
126 | const onClickScheduleTask = () => {
127 | BackgroundFetch.scheduleTask({
128 | taskId: 'com.transistorsoft.customtask',
129 | delay: 5000,
130 | forceAlarmManager: true
131 | }).then(() => {
132 | Alert.alert('scheduleTask', 'Scheduled task with delay: 5000ms');
133 | }).catch((error) => {
134 | Alert.alert('scheduleTask ERROR', error);
135 | });
136 | }
137 |
138 | /// Clear the Events list.
139 | ///
140 | const onClickClear = () => {
141 | Event.destroyAll();
142 | setEvents([]);
143 | }
144 |
145 | /// Fetch events renderer.
146 | ///
147 | const renderEvents = () => {
148 | if (!events.length) {
149 | return (
150 | Waiting for BackgroundFetch events...
151 | );
152 | }
153 | return events.slice().reverse().map(event => (
154 |
155 |
156 | {event.taskId} {event.isHeadless ? '[Headless]' : ''}
157 |
158 | {event.timestamp}
159 |
160 | ))
161 | }
162 |
163 | return (
164 |
165 |
166 |
167 |
168 |
169 | BGFetch Demo
170 |
171 |
172 |
175 | {renderEvents()}
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | );
187 | };
188 |
189 | const styles = StyleSheet.create({
190 | container: {
191 | flexDirection: 'column',
192 | flex: 1
193 | },
194 | title: {
195 | fontSize: 24,
196 | flex: 1,
197 | fontWeight: 'bold',
198 | color: Colors.black
199 | },
200 | eventList: {
201 | flex: 1,
202 | backgroundColor: Colors.white
203 | },
204 | event: {
205 | padding: 10,
206 | borderBottomWidth: 1,
207 | borderColor: Colors.lightGrey
208 | },
209 | taskId: {
210 | color: Colors.blue,
211 | fontSize: 16,
212 | fontWeight: 'bold'
213 | },
214 | headless: {
215 | fontWeight: 'bold'
216 | },
217 | timestamp: {
218 | color: Colors.black
219 | },
220 | toolbar: {
221 | height: 57,
222 | flexDirection: 'row',
223 | paddingLeft: 10,
224 | paddingRight: 10,
225 | alignItems: 'center',
226 | backgroundColor: Colors.gold
227 | },
228 |
229 | });
230 |
231 | export default App;
232 |
--------------------------------------------------------------------------------
/example/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
3 | ruby '2.7.5'
4 | gem 'cocoapods', '~> 1.11', '>= 1.11.2'
5 |
6 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | react-native-background-fetch Example App
2 | ============================================================
3 |
4 | # Installation
5 |
6 | 1. Clone this repo
7 |
8 | ```
9 | $ git clone
10 | $ cd example
11 | $ yarn install
12 |
13 | $ cd ios
14 | $ pod install
15 |
16 | # Edit the ios/FetchDemo.xcodeproj/project.pbxproj file and set both lines with DEVELOPMENT_TEAM to your own Team ID. This can be found at https://developer.apple.com/account under Membership.
17 |
18 | $ npx react-native run-android
19 | $ npx react-native run-ios
20 | ```
21 |
22 | :warning: __iOS__: Test on a real device. The new iOS 13 `BGTaskScheduler` API does not work on Simulators.
23 |
24 | # Simulating Events
25 |
26 | ## iOS
27 |
28 | #### :new: `BGTaskScheduler` API for iOS 13+
29 |
30 | - :warning: At the time of writing, the new task simulator does not yet work in Simulator; Only real devices.
31 | - See Apple docs [Starting and Terminating Tasks During Development](https://developer.apple.com/documentation/backgroundtasks/starting_and_terminating_tasks_during_development?language=objc)
32 | - After running your app in XCode, Click the `[||]` button to initiate a *Breakpoint*.
33 | - In the console `(lldb)`, paste the following command (**Note:** use cursor up/down keys to cycle through previously run commands):
34 | ```obj-c
35 | e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.transistorsoft.fetch"]
36 | ```
37 | - Click the `[ > ]` button to continue. The task will execute and the Callback function provided to **`BackgroundFetch.configure`** will receive the event.
38 |
39 |
40 | 
41 |
42 | 
43 |
44 | 
45 |
46 | #### Old `BackgroundFetch` API
47 | - Simulate background fetch events in XCode using **`Debug->Simulate Background Fetch`**
48 | - iOS can take some hours or even days to start a consistently scheduling background-fetch events since iOS schedules fetch events based upon the user's patterns of activity. If *Simulate Background Fetch* works, your can be **sure** that everything is working fine. You just need to wait.
49 |
50 | ## Android
51 |
52 | - Observe plugin logs in `$ adb logcat`:
53 | ```bash
54 | $ adb logcat *:S ReactNative:V ReactNativeJS:V TSBackgroundFetch:V
55 | ```
56 |
57 | - Simulate a background-fetch event on a device (insert *<your.application.id>*) (only works for sdk `21+`:
58 | ```bash
59 | $ ./scripts/simulate-fetch
60 | ```
61 |
62 |
--------------------------------------------------------------------------------
/example/__tests__/App-test.tsx:
--------------------------------------------------------------------------------
1 | /**
2 | * @format
3 | */
4 |
5 | import 'react-native';
6 | import React from 'react';
7 | import App from '../App';
8 |
9 | // Note: test renderer must be required after react-native.
10 | import renderer from 'react-test-renderer';
11 |
12 | it('renders correctly', () => {
13 | renderer.create();
14 | });
15 |
--------------------------------------------------------------------------------
/example/android/app/_BUCK:
--------------------------------------------------------------------------------
1 | # To learn about Buck see [Docs](https://buckbuild.com/).
2 | # To run your application with Buck:
3 | # - install Buck
4 | # - `npm start` - to start the packager
5 | # - `cd android`
6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
8 | # - `buck install -r android/app` - compile, install and run application
9 | #
10 |
11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
12 |
13 | lib_deps = []
14 |
15 | create_aar_targets(glob(["libs/*.aar"]))
16 |
17 | create_jar_targets(glob(["libs/*.jar"]))
18 |
19 | android_library(
20 | name = "all-libs",
21 | exported_deps = lib_deps,
22 | )
23 |
24 | android_library(
25 | name = "app-code",
26 | srcs = glob([
27 | "src/main/java/**/*.java",
28 | ]),
29 | deps = [
30 | ":all-libs",
31 | ":build_config",
32 | ":res",
33 | ],
34 | )
35 |
36 | android_build_config(
37 | name = "build_config",
38 | package = "com.fetchdemo",
39 | )
40 |
41 | android_resource(
42 | name = "res",
43 | package = "com.fetchdemo",
44 | res = "src/main/res",
45 | )
46 |
47 | android_binary(
48 | name = "app",
49 | keystore = "//android/keystores:debug",
50 | manifest = "src/main/AndroidManifest.xml",
51 | package_type = "debug",
52 | deps = [
53 | ":app-code",
54 | ],
55 | )
56 |
--------------------------------------------------------------------------------
/example/android/app/build_defs.bzl:
--------------------------------------------------------------------------------
1 | """Helper definitions to glob .aar and .jar targets"""
2 |
3 | def create_aar_targets(aarfiles):
4 | for aarfile in aarfiles:
5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
6 | lib_deps.append(":" + name)
7 | android_prebuilt_aar(
8 | name = name,
9 | aar = aarfile,
10 | )
11 |
12 | def create_jar_targets(jarfiles):
13 | for jarfile in jarfiles:
14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
15 | lib_deps.append(":" + name)
16 | prebuilt_jar(
17 | name = name,
18 | binary_jar = jarfile,
19 | )
20 |
--------------------------------------------------------------------------------
/example/android/app/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/transistorsoft/react-native-background-fetch/f682dbd0e1d4e1c943d032b66246e40e118ebec0/example/android/app/debug.keystore
--------------------------------------------------------------------------------
/example/android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/java/com/fetchdemo/ReactNativeFlipper.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) Facebook, Inc. and its affiliates.
3 | *
4 | *
This source code is licensed under the MIT license found in the LICENSE file in the root
5 | * directory of this source tree.
6 | */
7 | package com.fetchdemo;
8 |
9 | import android.content.Context;
10 | import com.facebook.flipper.android.AndroidFlipperClient;
11 | import com.facebook.flipper.android.utils.FlipperUtils;
12 | import com.facebook.flipper.core.FlipperClient;
13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20 | import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22 | import com.facebook.react.ReactInstanceEventListener;
23 | import com.facebook.react.ReactInstanceManager;
24 | import com.facebook.react.bridge.ReactContext;
25 | import com.facebook.react.modules.network.NetworkingModule;
26 | import okhttp3.OkHttpClient;
27 |
28 | public class ReactNativeFlipper {
29 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
30 | if (FlipperUtils.shouldEnableFlipper(context)) {
31 | final FlipperClient client = AndroidFlipperClient.getInstance(context);
32 |
33 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
34 | client.addPlugin(new ReactFlipperPlugin());
35 | client.addPlugin(new DatabasesFlipperPlugin(context));
36 | client.addPlugin(new SharedPreferencesFlipperPlugin(context));
37 | client.addPlugin(CrashReporterPlugin.getInstance());
38 |
39 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
40 | NetworkingModule.setCustomClientBuilder(
41 | new NetworkingModule.CustomClientBuilder() {
42 | @Override
43 | public void apply(OkHttpClient.Builder builder) {
44 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
45 | }
46 | });
47 | client.addPlugin(networkFlipperPlugin);
48 | client.start();
49 |
50 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
51 | // Hence we run if after all native modules have been initialized
52 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
53 | if (reactContext == null) {
54 | reactInstanceManager.addReactInstanceEventListener(
55 | new ReactInstanceEventListener() {
56 | @Override
57 | public void onReactContextInitialized(ReactContext reactContext) {
58 | reactInstanceManager.removeReactInstanceEventListener(this);
59 | reactContext.runOnNativeModulesQueueThread(
60 | new Runnable() {
61 | @Override
62 | public void run() {
63 | client.addPlugin(new FrescoFlipperPlugin());
64 | }
65 | });
66 | }
67 | });
68 | } else {
69 | client.addPlugin(new FrescoFlipperPlugin());
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/fetchdemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.fetchdemo;
2 |
3 | import com.facebook.react.ReactActivity;
4 | import com.facebook.react.ReactActivityDelegate;
5 | import com.facebook.react.ReactRootView;
6 |
7 | public class MainActivity extends ReactActivity {
8 |
9 | /**
10 | * Returns the name of the main component registered from JavaScript. This is used to schedule
11 | * rendering of the component.
12 | */
13 | @Override
14 | protected String getMainComponentName() {
15 | return "FetchDemo";
16 | }
17 |
18 | /**
19 | * Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
20 | * you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
21 | * (Paper).
22 | */
23 | @Override
24 | protected ReactActivityDelegate createReactActivityDelegate() {
25 | return new MainActivityDelegate(this, getMainComponentName());
26 | }
27 | public static class MainActivityDelegate extends ReactActivityDelegate {
28 | public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
29 | super(activity, mainComponentName);
30 | }
31 | @Override
32 | protected ReactRootView createRootView() {
33 | ReactRootView reactRootView = new ReactRootView(getContext());
34 | // If you opted-in for the New Architecture, we enable the Fabric Renderer.
35 | reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
36 | return reactRootView;
37 | }
38 | @Override
39 | protected boolean isConcurrentRootEnabled() {
40 | // If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
41 | // More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
42 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/fetchdemo/MainApplication.java:
--------------------------------------------------------------------------------
1 | package com.fetchdemo;
2 |
3 | import android.app.Application;
4 | import android.content.Context;
5 | import android.os.StrictMode;
6 |
7 | import com.facebook.react.PackageList;
8 | import com.facebook.react.ReactApplication;
9 | import com.facebook.react.ReactInstanceManager;
10 | import com.facebook.react.ReactNativeHost;
11 | import com.facebook.react.ReactPackage;
12 | import com.facebook.react.config.ReactFeatureFlags;
13 | import com.facebook.soloader.SoLoader;
14 | import com.fetchdemo.newarchitecture.MainApplicationReactNativeHost;
15 | import java.lang.reflect.InvocationTargetException;
16 | import java.util.List;
17 |
18 | public class MainApplication extends Application implements ReactApplication {
19 |
20 | private final ReactNativeHost mReactNativeHost =
21 | new ReactNativeHost(this) {
22 | @Override
23 | public boolean getUseDeveloperSupport() {
24 | return BuildConfig.DEBUG;
25 | }
26 |
27 | @Override
28 | protected List getPackages() {
29 | @SuppressWarnings("UnnecessaryLocalVariable")
30 | List packages = new PackageList(this).getPackages();
31 | // Packages that cannot be autolinked yet can be added manually here, for example:
32 | // packages.add(new MyReactNativePackage());
33 | return packages;
34 | }
35 |
36 | @Override
37 | protected String getJSMainModuleName() {
38 | return "index";
39 | }
40 | };
41 |
42 | private final ReactNativeHost mNewArchitectureNativeHost = new MainApplicationReactNativeHost(this);
43 |
44 | @Override
45 | public ReactNativeHost getReactNativeHost() {
46 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
47 | return mNewArchitectureNativeHost;
48 | } else {
49 | return mReactNativeHost;
50 | }
51 | }
52 |
53 | @Override
54 | public void onCreate() {
55 | StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
56 | .detectDiskReads()
57 | .detectDiskWrites()
58 | .detectAll()
59 | .penaltyLog()
60 | .build());
61 | StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
62 | .detectLeakedSqlLiteObjects()
63 | .detectLeakedClosableObjects()
64 | .penaltyLog()
65 | .penaltyDeath()
66 | .build());
67 |
68 | super.onCreate();
69 | // If you opted-in for the New Architecture, we enable the TurboModule system
70 | ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
71 | SoLoader.init(this, /* native exopackage */ false);
72 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
73 | }
74 |
75 | /**
76 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like
77 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
78 | *
79 | * @param context
80 | * @param reactInstanceManager
81 | */
82 | private static void initializeFlipper(
83 | Context context, ReactInstanceManager reactInstanceManager) {
84 | if (BuildConfig.DEBUG) {
85 | try {
86 | /*
87 | We use reflection here to pick up the class that initializes Flipper,
88 | since Flipper library is not available in release mode
89 | */
90 | Class> aClass = Class.forName("com.fetchdemo.ReactNativeFlipper");
91 | aClass
92 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
93 | .invoke(null, context, reactInstanceManager);
94 | } catch (ClassNotFoundException e) {
95 | e.printStackTrace();
96 | } catch (NoSuchMethodException e) {
97 | e.printStackTrace();
98 | } catch (IllegalAccessException e) {
99 | e.printStackTrace();
100 | } catch (InvocationTargetException e) {
101 | e.printStackTrace();
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/fetchdemo/newarchitecture/MainApplicationReactNativeHost.java:
--------------------------------------------------------------------------------
1 | package com.fetchdemo.newarchitecture;
2 |
3 | import android.app.Application;
4 | import androidx.annotation.NonNull;
5 | import com.facebook.react.PackageList;
6 | import com.facebook.react.ReactInstanceManager;
7 | import com.facebook.react.ReactNativeHost;
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
10 | import com.facebook.react.bridge.JSIModulePackage;
11 | import com.facebook.react.bridge.JSIModuleProvider;
12 | import com.facebook.react.bridge.JSIModuleSpec;
13 | import com.facebook.react.bridge.JSIModuleType;
14 | import com.facebook.react.bridge.JavaScriptContextHolder;
15 | import com.facebook.react.bridge.ReactApplicationContext;
16 | import com.facebook.react.bridge.UIManager;
17 | import com.facebook.react.fabric.ComponentFactory;
18 | import com.facebook.react.fabric.CoreComponentsRegistry;
19 | import com.facebook.react.fabric.FabricJSIModuleProvider;
20 | import com.facebook.react.fabric.ReactNativeConfig;
21 | import com.facebook.react.uimanager.ViewManagerRegistry;
22 | import com.fetchdemo.BuildConfig;
23 | import com.fetchdemo.newarchitecture.components.MainComponentsRegistry;
24 | import com.fetchdemo.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 |
28 | /**
29 | * A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
30 | * TurboModule delegates and the Fabric Renderer.
31 | *
32 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
33 | * `newArchEnabled` property). Is ignored otherwise.
34 | */
35 | public class MainApplicationReactNativeHost extends ReactNativeHost {
36 | public MainApplicationReactNativeHost(Application application) {
37 | super(application);
38 | }
39 |
40 | @Override
41 | public boolean getUseDeveloperSupport() {
42 | return BuildConfig.DEBUG;
43 | }
44 |
45 | @Override
46 | protected List getPackages() {
47 | List packages = new PackageList(this).getPackages();
48 | // Packages that cannot be autolinked yet can be added manually here, for example:
49 | // packages.add(new MyReactNativePackage());
50 | // TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
51 | // packages.add(new TurboReactPackage() { ... });
52 | // If you have custom Fabric Components, their ViewManagers should also be loaded here
53 | // inside a ReactPackage.
54 | return packages;
55 | }
56 |
57 | @Override
58 | protected String getJSMainModuleName() {
59 | return "index";
60 | }
61 |
62 | @NonNull
63 | @Override
64 | protected ReactPackageTurboModuleManagerDelegate.Builder
65 | getReactPackageTurboModuleManagerDelegateBuilder() {
66 | // Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
67 | // for the new architecture and to use TurboModules correctly.
68 | return new MainApplicationTurboModuleManagerDelegate.Builder();
69 | }
70 |
71 | @Override
72 | protected JSIModulePackage getJSIModulePackage() {
73 | return new JSIModulePackage() {
74 | @Override
75 | public List getJSIModules(
76 | final ReactApplicationContext reactApplicationContext,
77 | final JavaScriptContextHolder jsContext) {
78 | final List specs = new ArrayList<>();
79 |
80 | // Here we provide a new JSIModuleSpec that will be responsible of providing the
81 | // custom Fabric Components.
82 | specs.add(
83 | new JSIModuleSpec() {
84 | @Override
85 | public JSIModuleType getJSIModuleType() {
86 | return JSIModuleType.UIManager;
87 | }
88 |
89 | @Override
90 | public JSIModuleProvider getJSIModuleProvider() {
91 | final ComponentFactory componentFactory = new ComponentFactory();
92 | CoreComponentsRegistry.register(componentFactory);
93 |
94 | // Here we register a Components Registry.
95 | // The one that is generated with the template contains no components
96 | // and just provides you the one from React Native core.
97 | MainComponentsRegistry.register(componentFactory);
98 |
99 | final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
100 |
101 | ViewManagerRegistry viewManagerRegistry =
102 | new ViewManagerRegistry(
103 | reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
104 |
105 | return new FabricJSIModuleProvider(
106 | reactApplicationContext,
107 | componentFactory,
108 | ReactNativeConfig.DEFAULT_CONFIG,
109 | viewManagerRegistry);
110 | }
111 | });
112 | return specs;
113 | }
114 | };
115 | }
116 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/fetchdemo/newarchitecture/components/MainComponentsRegistry.java:
--------------------------------------------------------------------------------
1 | package com.fetchdemo.newarchitecture.components;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.proguard.annotations.DoNotStrip;
5 | import com.facebook.react.fabric.ComponentFactory;
6 | import com.facebook.soloader.SoLoader;
7 |
8 | /**
9 | * Class responsible to load the custom Fabric Components. This class has native methods and needs a
10 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
11 | * folder for you).
12 | *
13 | *
Please note that this class is used ONLY if you opt-in for the New Architecture (see the
14 | * `newArchEnabled` property). Is ignored otherwise.
15 | */
16 | @DoNotStrip
17 | public class MainComponentsRegistry {
18 | static {
19 | SoLoader.loadLibrary("fabricjni");
20 | }
21 |
22 | @DoNotStrip private final HybridData mHybridData;
23 |
24 | @DoNotStrip
25 | private native HybridData initHybrid(ComponentFactory componentFactory);
26 |
27 | @DoNotStrip
28 | private MainComponentsRegistry(ComponentFactory componentFactory) {
29 | mHybridData = initHybrid(componentFactory);
30 | }
31 |
32 | @DoNotStrip
33 | public static MainComponentsRegistry register(ComponentFactory componentFactory) {
34 | return new MainComponentsRegistry(componentFactory);
35 | }
36 | }
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/fetchdemo/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate.java:
--------------------------------------------------------------------------------
1 | package com.fetchdemo.newarchitecture.modules;
2 |
3 | import com.facebook.jni.HybridData;
4 | import com.facebook.react.ReactPackage;
5 | import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
6 | import com.facebook.react.bridge.ReactApplicationContext;
7 | import com.facebook.soloader.SoLoader;
8 | import java.util.List;
9 |
10 | /**
11 | * Class responsible to load the TurboModules. This class has native methods and needs a
12 | * corresponding C++ implementation/header file to work correctly (already placed inside the jni/
13 | * folder for you).
14 | *
15 | *