diff --git a/CHANGELOG.md b/CHANGELOG.md index 437df08..c60e99f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## [4.1.1] — 2022-06-28 +* Fix issue for react-native 0.69: They made a breaking change with the old, unused react-native.config.js, causing builds to fail. Simply delete the file `react-native.config.js`. + +## [4.1.0] — 2022-04-06 +* [Android] Add new permission required for Android 12: android.permission.SCHEDULE_EXACT_ALARM + ## [4.0.5] — 2022-02-10 * [Fixed][iOS] Remove obsolete `__has_include("RCTEventEmitter.h")` code which was breaking Expo apps. diff --git a/package.json b/package.json index 8ce4506..b1825d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-background-fetch", - "version": "4.1.0", + "version": "4.1.1", "description": "iOS & Android BackgroundFetch API implementation for React Native", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" @@ -21,12 +21,6 @@ "bugs": { "url": "https://github.com/transistorsoft/react-native-background-fetch/issues" }, - "rnpm": { - "commands": { - "postlink": "node node_modules/react-native-background-fetch/scripts/postlink.js", - "postunlink": "node node_modules/react-native-background-fetch/scripts/postunlink.js" - } - }, "homepage": "https://transistorsoft.github.io/react-native-background-fetch", "peerDependencies": { "react-native": ">=0.28.0" diff --git a/react-native.config.js b/react-native.config.js deleted file mode 100644 index 7386de9..0000000 --- a/react-native.config.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - // config for a library is scoped under "dependency" key - dependency: { - platforms: { - ios: {}, - android: {}, // projects are grouped into "platforms" - }, - assets: [] - }, -}; diff --git a/scripts/postlink.js b/scripts/postlink.js deleted file mode 100755 index daf2daf..0000000 --- a/scripts/postlink.js +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const fs = require('fs'); -const xcode = require('xcode'); -const PbxFile = require('xcode/lib/pbxFile'); -const helpers = require('./xcode-helpers'); - -const projectDirectory = process.cwd(); -const moduleDirectory = path.resolve(__dirname, '..'); -const sourceDirectory = path.join(projectDirectory, 'ios'); -const xcodeProjectDirectory = helpers.findProject(sourceDirectory); - -const projectConfig = { - sourceDir: sourceDirectory, - pbxprojPath: path.join( - projectDirectory, - 'ios', - xcodeProjectDirectory, - 'project.pbxproj' - ), -}; - -const pathToFramework = path.relative( - projectConfig.sourceDir, - path.join( - moduleDirectory, - 'ios', - 'RNBackgroundFetch', - 'TSBackgroundFetch.framework' - ) -); -const pathToAppdelegateExtension = path.relative( - projectConfig.sourceDir, - path.join( - moduleDirectory, - 'ios', - 'RNBackgroundFetch', - 'RNBackgroundFetch+AppDelegate.m' - ) -); - -const project = xcode.project(projectConfig.pbxprojPath).parseSync(); -// Monkey-patch XCode to search PBXGroups with ignore-case. -project.findPBXGroupKeyAndType = helpers.findPBXGroupKeyAndType; - - -/** - * There is a method in node-xcode that offers similar functionality than what - * is implemented below `addFramework` (https://github.com/alunny/node-xcode/blob/ffb938b/lib/pbxProject.js#L300) - * but unfortunately it won't work for our use-case because there are two other - * methods in node-xcode that are being used by `addFramework` that don't work - * as expected: - * 1 `addToFrameworksPbxGroup` fails if no group with the name "Frameworks" exists - * https://github.com/alunny/node-xcode/blob/ffb938b/lib/pbxProject.js#L641 - * - https://github.com/alunny/node-xcode/issues/43 - * - this issue could be worked around by just checking if the group exists and - * creating it if it doesn't exist before executing `addFramework` - * 2 `addToFrameworkSearchPaths` doesn't work with react-native: - * https://github.com/alunny/node-xcode/blob/ffb938b/lib/pbxProject.js#L1125 - * - https://github.com/alunny/node-xcode/issues/91 - * - https://github.com/alunny/node-xcode/pull/99 - * - the issue there is that https://github.com/alunny/node-xcode/blob/ffb938b/lib/pbxProject.js#L1133 - * in react-native projects the "PRODUCT_NAME" is "$(TARGET_NAME)", so it won't - * be visited by this method. - * And even if the name would be correct it still wouldn't work correctly for - * react-native projects, because not all targets should get the library added - * for example: react-native creates *tests and *tvOs and *tvOstests targets. - */ -const file = new PbxFile(pathToFramework); -file.uuid = project.generateUuid(); -file.fileRef = project.generateUuid(); -file.path = pathToFramework; -file.target = project.getFirstTarget().uuid; - -if (!project.hasFile(file.path)) { - project.addToPbxBuildFileSection(file); - project.addToPbxFileReferenceSection(file); - // addToFrameworksPbxGroup crashes when it can't find a group named "Frameworks" - if (!project.pbxGroupByName('Frameworks')) { - project.addPbxGroup([], 'Frameworks'); - } - project.addToFrameworksPbxGroup(file); - project.addToPbxFrameworksBuildPhase(file); -} - -const podFile = path.join(sourceDirectory, 'Podfile'); -const hasPodfile = fs.existsSync(podFile); - -if (!hasPodfile) { - helpers.addToFrameworkSearchPaths( - project, - '$(PROJECT_DIR)/' + - path.relative( - projectConfig.sourceDir, - path.join(moduleDirectory, 'ios') - ), - true - ); -} - -// enable BackgroundModes in xcode project without overriding any previously -// defined values in the project file. -// That's why we deep clone all previously defined target attributes and extend -// them with our target attributes. -const targetAttributes = helpers.getTargetAttributes(project); -const systemCapabilities = Object.assign({}, (targetAttributes.SystemCapabilities || {}), { - 'com.apple.BackgroundModes': Object.assign( - {}, - targetAttributes['com.apple.BackgroundModes'] || {}, - { enabled: true } - ), -}); -if (targetAttributes.SystemCapabilities) { - targetAttributes.SystemCapabilities = systemCapabilities; -} else { - project.addTargetAttribute('SystemCapabilities', systemCapabilities); -} - -// add "fetch" background mode to Info.plist file -const plist = helpers.readPlist(projectConfig.sourceDir, project); -const UIBackgroundModes = plist.UIBackgroundModes || []; -if (UIBackgroundModes.indexOf('fetch') === -1) { - plist.UIBackgroundModes = UIBackgroundModes.concat('fetch'); -} - -// Add RNBackgroundFetch+AppDelegate.m extension. -const groupName = xcodeProjectDirectory.replace('.xcodeproj', ''); -var projectGroup = project.findPBXGroupKey({ name: groupName }) || project.findPBXGroupKey({path: groupName}); - -if (projectGroup) { - project.addSourceFile( - pathToAppdelegateExtension, - { target: project.getFirstTarget().uuid }, - projectGroup - ); -} else { - var red = "\x1b[31m"; - var yellow = "\x1b[33m" - var colorReset = '\x1b[0m'; - console.log(yellow, project.hash.project.objects.PBXGroup); - console.error(red, '[react-native-background-fetch] LINK ERROR: Failed to find projectGroup PBXGroup: ', groupName); - console.error(red, '[react-native-background-fetch] Failed to add RNBackgroundFetch+AppDelegate.m. See Manual Setup instructions to add this file to your project.'); - console.error(red, '[react-native-bacgkround-fetch] Please post an issue at Github, including all the output above'); - console.error(colorReset); -} - -helpers.writePlist(projectConfig.sourceDir, project, plist); -fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync()); - - - diff --git a/scripts/postunlink.js b/scripts/postunlink.js deleted file mode 100755 index 7f2fdd6..0000000 --- a/scripts/postunlink.js +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/env node - -const path = require('path'); -const fs = require('fs'); -const xcode = require('xcode'); -const PbxFile = require('xcode/lib/pbxFile'); -const helpers = require('./xcode-helpers'); - -const projectDirectory = process.cwd(); -const moduleDirectory = path.resolve(__dirname, '..'); -const sourceDirectory = path.join(projectDirectory, 'ios'); -const xcodeProjectDirectory = helpers.findProject(sourceDirectory); - -const projectConfig = { - sourceDir: sourceDirectory, - pbxprojPath: path.join( - projectDirectory, - 'ios', - xcodeProjectDirectory, - 'project.pbxproj' - ), -}; - -const pathToFramework = path.relative( - projectConfig.sourceDir, - path.join( - moduleDirectory, - 'ios', - 'RNBackgroundFetch', - 'TSBackgroundFetch.framework' - ) -); -const pathToAppdelegateExtension = path.relative( - projectConfig.sourceDir, - path.join( - moduleDirectory, - 'ios', - 'RNBackgroundFetch', - 'RNBackgroundFetch+AppDelegate.m' - ) -); - - -const project = xcode.project(projectConfig.pbxprojPath).parseSync(); -// Monkey-patch XCode to search PBXGroups with ignore-case. -project.findPBXGroupKeyAndType = helpers.findPBXGroupKeyAndType; - -const file = new PbxFile(pathToFramework); -file.target = project.getFirstTarget().uuid; - -project.removeFromPbxBuildFileSection(file); -project.removeFromPbxFileReferenceSection(file); -if (project.pbxGroupByName('Frameworks')) { - project.removeFromFrameworksPbxGroup(file); -} -project.removeFromPbxFrameworksBuildPhase(file); - -const podFile = path.join(sourceDirectory, 'Podfile'); -const hasPodfile = fs.existsSync(podFile); - -if (!hasPodfile) { - helpers.removeFromFrameworkSearchPaths( - project, - '$(PROJECT_DIR)/' + - path.relative( - projectConfig.sourceDir, - path.join(moduleDirectory, 'ios') - ) - ); -} - -// disable BackgroundModes and remove "fetch" mode from plist file -const systemCapabilities = helpers.getTargetAttributes(project).SystemCapabilities; -if (systemCapabilities && systemCapabilities['com.apple.BackgroundModes']) { - delete systemCapabilities['com.apple.BackgroundModes'].enabled; - if (Object.keys(systemCapabilities['com.apple.BackgroundModes']).length === 0) { - delete systemCapabilities['com.apple.BackgroundModes']; - } - - if (Object.keys(systemCapabilities).length === 0) { - project.removeTargetAttribute('SystemCapabilities'); - } -} - -const plist = helpers.readPlist(projectConfig.sourceDir, project); -if (Array.isArray(plist.UIBackgroundModes)) { - plist.UIBackgroundModes = plist.UIBackgroundModes.filter( - mode => mode !== 'fetch' - ); - if (plist.UIBackgroundModes.length === 0) { - delete plist.UIBackgroundModes; - } -} - -// remove RNBackgroundFetch+AppDelegate extension -const groupName = xcodeProjectDirectory.replace('.xcodeproj', ''); -var projectGroup = project.findPBXGroupKey({ name: groupName }) || project.findPBXGroupKey({path: groupName}); - -if (projectGroup) { - project.removeSourceFile( - pathToAppdelegateExtension, - { target: project.getFirstTarget().uuid }, - projectGroup - ); -} else { - var red = "\x1b[31m"; - var yellow = "\x1b[33m" - var colorReset = '\x1b[0m'; - console.log(yellow, project.hash.project.objects.PBXGroup); - console.error(red, '[react-native-background-fetch] UNLINK ERROR: Failed to find projectGroup PBXGroup: ', groupName); - console.error(red, '[react-native-background-fetch] Failed to remove RNBackgroundFetch+AppDelegate.m. See Manual Setup instructions to remove this file from your project.'); - console.error(red, '[react-native-bacgkround-fetch] Please post an issue at Github, including all the output above'); - console.error(colorReset); -} - -helpers.writePlist(projectConfig.sourceDir, project, plist); -fs.writeFileSync(projectConfig.pbxprojPath, project.writeSync()); - -//// -// Android -// - Remove maven url -// maven { -// url "$rootDir/../node_modules/react-native-background-fetch/android/libs" -// } -// -const androidSrcDir = path.join(projectDirectory, 'android'); -const gradleFile = path.join(androidSrcDir, 'build.gradle'); -const moduleName = (process.platform === 'win32') ? moduleDirectory.split('\\').pop() : moduleDirectory.split('/').pop(); - -fs.readFile(gradleFile, 'utf8', function (err,data) { - if (err) { - return console.log(err); - } - var re = new RegExp("[\\t?\\s?]+maven\\s?\\{[\\n?\\s?\\t?]+url.*" + moduleName + "\\/.*[\\n?\\t?\\s?]+\\}", "gm"); - - if (data.match(re)) { - fs.writeFile(gradleFile, data.replace(re, ''), 'utf8', function (err) { - if (err) return console.log(err); - }); - } -}); - diff --git a/scripts/xcode-helpers.js b/scripts/xcode-helpers.js deleted file mode 100644 index 6067a25..0000000 --- a/scripts/xcode-helpers.js +++ /dev/null @@ -1,219 +0,0 @@ -const path = require('path'); -const fs = require('fs'); -const glob = require('glob'); -// unfortunately we can't use the 'plist' module at the moment for parsing -// because it has a few issues with empty strings and keys. -// There are several issues and PRs on that repository open though and hopefully -// we can revert back to only using one module once they're merged. -const plistParser = require('fast-plist'); -const plistWriter = require('plist'); - -// The getBuildProperty method of the 'xcode' project is a bit naive in that it -// doesn't take a specific target but iterates over all of them and doesn't have -// an exit condition if a property has been found. -// Which in the case of react-native projects usually is the tvOS target because -// it comes last. -function getBuildProperty(project, property) { - const firstTarget = project.getFirstTarget().firstTarget; - const configurationList = project.pbxXCConfigurationList()[ - firstTarget.buildConfigurationList - ]; - const defaultBuildConfiguration = configurationList.buildConfigurations.reduce( - (acc, config) => { - const buildSection = project.pbxXCBuildConfigurationSection()[ - config.value - ]; - return buildSection.name === - configurationList.defaultConfigurationName - ? buildSection - : acc; - }, - configurationList.buildConfigurations[0] - ); - - return defaultBuildConfiguration.buildSettings[property]; -} - -function getPlistPath(sourceDir, project) { - const plistFile = getBuildProperty(project, 'INFOPLIST_FILE'); - if (!plistFile) { - return null; - } - return path.join( - sourceDir, - plistFile.replace(/"/g, '').replace('$(SRCROOT)', '') - ); -} - -function readPlist(sourceDir, project) { - const plistPath = getPlistPath(sourceDir, project); - if (!plistPath || !fs.existsSync(plistPath)) { - return null; - } - return plistParser.parse(fs.readFileSync(plistPath, 'utf-8')); -} - -function writePlist(sourceDir, project, plist) { - fs.writeFileSync( - getPlistPath(sourceDir, project), - plistWriter.build(plist) - ); -} - -// based on: https://github.com/facebook/react-native/blob/545072b/local-cli/link/ios/mapHeaderSearchPaths.js#L5 -function eachBuildConfiguration(project, predicate, callback) { - const config = project.pbxXCBuildConfigurationSection(); - Object.keys(config) - .filter(ref => ref.indexOf('_comment') === -1) - .filter(ref => predicate(config[ref])) - .forEach(ref => callback(config[ref])); -} - -// this is being used to determine whether the current target is a react-native -// project: https://github.com/facebook/react-native/blob/545072b/local-cli/link/ios/mapHeaderSearchPaths.js#L31 -function hasLCPlusPlus(config) { - return (config.buildSettings.OTHER_LDFLAGS || []).indexOf('"-lc++"') >= 0; -} - -// based on: https://github.com/facebook/react-native/blob/1490ab1/local-cli/core/ios/findProject.js -function findProject(folder) { - const GLOB_PATTERN = '**/*.xcodeproj'; - const TEST_PROJECTS = /test|example|sample/i; - const IOS_BASE = 'ios'; - const GLOB_EXCLUDE_PATTERN = ['**/@(Carthage|Pods|node_modules)/**']; - - const projects = glob - .sync(GLOB_PATTERN, { - cwd: folder, - ignore: GLOB_EXCLUDE_PATTERN, - }) - .filter(project => { - return path.dirname(project) === IOS_BASE || !TEST_PROJECTS.test(project); - }) - .sort((projectA, projectB) => { - return path.dirname(projectA) === IOS_BASE ? -1 : 1; - }); - - if (projects.length === 0) { - return null; - } - - return projects[0]; -}; - -function addToFrameworkSearchPaths(project, path, recursive) { - eachBuildConfiguration(project, hasLCPlusPlus, config => { - if (!config.buildSettings.FRAMEWORK_SEARCH_PATHS) { - config.buildSettings.FRAMEWORK_SEARCH_PATHS = []; - } else if (typeof config.buildSettings.FRAMEWORK_SEARCH_PATHS === 'string') { - config.buildSettings.FRAMEWORK_SEARCH_PATHS = [config.buildSettings.FRAMEWORK_SEARCH_PATHS]; - } - const fullPath = '"' + path + (recursive ? '/**' : '') + '"'; - - if ( - config.buildSettings.FRAMEWORK_SEARCH_PATHS.indexOf(fullPath) === -1 - ) { - config.buildSettings.FRAMEWORK_SEARCH_PATHS = config.buildSettings.FRAMEWORK_SEARCH_PATHS.concat( - fullPath - ); - } - }); -} - -function removeFromFrameworkSearchPaths(project, path) { - eachBuildConfiguration(project, hasLCPlusPlus, config => { - if (!config.buildSettings.FRAMEWORK_SEARCH_PATHS) { - config.buildSettings.FRAMEWORK_SEARCH_PATHS = []; - } else if (typeof config.buildSettings.FRAMEWORK_SEARCH_PATHS === 'string') { - config.buildSettings.FRAMEWORK_SEARCH_PATHS = [config.buildSettings.FRAMEWORK_SEARCH_PATHS]; - } - - const fullPath = unquote(path) + '/**'; - - config.buildSettings.FRAMEWORK_SEARCH_PATHS = config.buildSettings.FRAMEWORK_SEARCH_PATHS.filter( - searchPath => - unquote(searchPath) !== unquote(path) && - unquote(searchPath) !== fullPath - ); - }); -} - -// The node-xcode library doesn't offer a method to get all target attributes, -// so we'll have to implement it ourselves. -function getTargetAttributes(project, target) { - var attributes = project.getFirstProject()['firstProject']['attributes']; - target = target || project.getFirstTarget(); - - if (attributes['TargetAttributes'] === undefined) { - attributes['TargetAttributes'] = {}; - } - - if (attributes['TargetAttributes'][target.uuid] === undefined) { - attributes['TargetAttributes'][target.uuid] = {}; - } - - return attributes['TargetAttributes'][target.uuid]; -} - -function unquote(str) { - return (str || '').replace(/^"(.*)"$/, '$1'); -} - -/** -* Monkey-patch xcode module to ignore case when comparing group.name / group.path -*/ -function findPBXGroupKeyAndType() { - COMMENT_KEY = /_comment$/; - - return function(criteria, groupType) { - var groups = this.hash.project.objects[groupType]; - var target; - - if (criteria) { - if (criteria.name) { - criteria.name = criteria.name.toLowerCase(); - } - if (criteria.path) { - criteria.path = criteria.path.toLowerCase(); - } - } - for (var key in groups) { - // only look for comments - if (COMMENT_KEY.test(key)) continue; - - var group = groups[key]; - if (criteria && criteria.path && criteria.name) { - if ((group.path && (criteria.path === group.path.toLowerCase())) && (group.name && (criteria.name === group.name.toLowerCase())) ) { - target = key; - break - } - } - else if (criteria && criteria.path) { - if (group.path && (criteria.path === group.path.toLowerCase())) { - target = key; - break - } - } - else if (criteria && criteria.name) { - if (group.name && (criteria.name === group.name.toLowerCase())) { - target = key; - break - } - } - } - return target; - } -} - - -module.exports = { - getBuildProperty: getBuildProperty, - getPlistPath: getPlistPath, - readPlist: readPlist, - writePlist: writePlist, - getTargetAttributes: getTargetAttributes, - addToFrameworkSearchPaths: addToFrameworkSearchPaths, - removeFromFrameworkSearchPaths: removeFromFrameworkSearchPaths, - findProject: findProject, - findPBXGroupKeyAndType: findPBXGroupKeyAndType() -};