Compare commits

..
Author SHA1 Message Date
semantic-release-bot fc16d69ba6 chore: 2.0.0
## @config-plugins/react-native-pdf [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-08-04)

### ⚠ BREAKING CHANGES

* add SDK 45 support (#79)

### Features

* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))

### Other chores

* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
2022-08-04 16:53:20 +00:00
Fabrizio Rizzonelli bf11a17a81 docs: added expo-appcenter to the list of plugin (#95) 2022-08-04 18:50:24 +02:00
semantic-release-bot b3c6210ffc chore: 2.0.1
### @config-plugins/react-native-ble-plx [2.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-07-25)

### Bug Fixes

* **react-native-ble-plx:** Added new Bluetooth specific permission for Android 12 (SDK 31). ([#91](https://github.com/expo/config-plugins/issues/91)) ([d3df63f](https://github.com/expo/config-plugins/commit/d3df63fbb2344251b9b371959de3ce6e4b9ab0cd))
2022-07-25 12:57:23 +00:00
Tom d3df63fbb2 fix(react-native-ble-plx): Added new Bluetooth specific permission for Android 12 (SDK 31). (#91)
* fix(react-native-ble-plx): Added new Bluetooth specific permission for Android SDK 31.

Expo SDK 45 targets Android SDK 31 which requires new Bluetooth specific permissions. Without these new permissions Android 12 (SDK 31) devices don't get access to BLE.

* Update README.md

* chore(react-native-ble-plx): Added `tools:targetApi="31"` to Android Manifest (for Lint).
2022-07-25 14:54:10 +02:00
semantic-release-bot 057c6bd978 chore: 2.0.0
## @config-plugins/react-native-callkeep [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-07-25)

### ⚠ BREAKING CHANGES

* add SDK 45 support (#79)

### Features

* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))

### Other chores

* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
2022-07-25 11:16:39 +00:00
Michael WoodandEvan Bacon 3fbc237fd6 Add react-native-multiple-image-picker (#92)
Co-authored-by: Evan Bacon <[email protected]>
2022-07-25 13:13:39 +02:00
Joseph Odunsi 6603ab3215 Update README.md (#93)
Add shopify flashlist
2022-07-25 13:13:03 +02:00
semantic-release-bot 9f49f02401 chore: 1.0.0
## @config-plugins/react-native-siri-shortcut 1.0.0 (2022-07-12)

### Features

* **siri-shortcut:** Add config plugin ([#86](https://github.com/expo/config-plugins/issues/86)) ([226b2a6](https://github.com/expo/config-plugins/commit/226b2a6412ad3fe75c98952831fab5a63254d19f))

### Other chores

* **react-native-siri-shortcut:** add tests ([#88](https://github.com/expo/config-plugins/issues/88)) ([994fadc](https://github.com/expo/config-plugins/commit/994fadc8ddf9ee858f2ccb7d544674f107f7f9ad))
2022-07-12 12:04:10 +00:00
Evan Bacon 14dc560092 Update README.md 2022-07-12 14:01:17 +02:00
Evan Bacon 2dcaff6772 Update README.md 2022-07-12 13:17:20 +02:00
Evan Bacon 68190997b6 Update README.md 2022-07-12 10:39:42 +02:00
semantic-release-bot 74f55fc342 chore: 2.0.2
### @config-plugins/ios-stickers [2.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-06-30)

### Other chores

* **deps-dev:** bump memfs in /packages/ios-stickers ([#83](https://github.com/expo/config-plugins/issues/83)) ([764a047](https://github.com/expo/config-plugins/commit/764a04710bea6e66dbc6d0065812acb1591435fb))
2022-06-30 17:32:49 +00:00
Evan Bacon e32378e8ed Add App Clips and Safari Extensions to Awesome list 2022-06-30 19:29:09 +02:00
dependabot[bot] 764a04710b chore(deps-dev): bump memfs in /packages/ios-stickers (#83) 2022-06-18 18:06:21 +02:00
Eugene Nagorny 837602af36 Update README.md (#89) 2022-06-18 18:04:46 +02:00
semantic-release-bot af22acc509 chore: 2.0.0
## @config-plugins/react-native-dynamic-app-icon [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-06-14)

### ⚠ BREAKING CHANGES

* add SDK 45 support (#79)

### Features

* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))

### Other chores

* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
2022-06-14 12:21:20 +00:00
Evan Bacon 994fadc8dd chore(react-native-siri-shortcut): add tests (#88)
* add: tests for siri

* add: unit tests

* chore: update repo settings

* chore: noop android

* Update withReactNativeSiriShortcut.ts
2022-06-14 14:17:45 +02:00
40 changed files with 1393 additions and 55 deletions

No files matched your search

+1
View File
@@ -42,6 +42,7 @@ body:
- '@config-plugins/react-native-google-cast' - '@config-plugins/react-native-google-cast'
- '@config-plugins/react-native-pdf' - '@config-plugins/react-native-pdf'
- '@config-plugins/react-native-quick-actions' - '@config-plugins/react-native-quick-actions'
- '@config-plugins/react-native-siri-shortcut'
- '@config-plugins/react-native-webrtc' - '@config-plugins/react-native-webrtc'
validations: validations:
required: true required: true
+3
View File
@@ -39,6 +39,9 @@ contact_links:
- about: A react-native interface for Touch 3D home screen quick actions - about: A react-native interface for Touch 3D home screen quick actions
name: 📦 react-native-quick-actions issues name: 📦 react-native-quick-actions issues
url: https://github.com/jordanbyron/react-native-quick-actions/issues url: https://github.com/jordanbyron/react-native-quick-actions/issues
- about: A React Native library that enables you to use iOS 12+ Siri Shortcuts.
name: 📦 react-native-siri-shortcut issues
url: https://github.com/Gustash/react-native-siri-shortcut/issues
- about: WebRTC for React Native - about: WebRTC for React Native
name: 📦 react-native-webrtc issues name: 📦 react-native-webrtc issues
url: https://github.com/react-native-webrtc/react-native-webrtc/issues url: https://github.com/react-native-webrtc/react-native-webrtc/issues
+6
View File
@@ -83,6 +83,12 @@ updates:
interval: daily interval: daily
time: '09:00' time: '09:00'
timezone: America/Los_Angeles timezone: America/Los_Angeles
- package-ecosystem: npm
directory: packages/react-native-siri-shortcut
schedule:
interval: daily
time: '09:00'
timezone: America/Los_Angeles
- package-ecosystem: npm - package-ecosystem: npm
directory: packages/react-native-webrtc directory: packages/react-native-webrtc
schedule: schedule:
+1
View File
@@ -41,6 +41,7 @@ jobs:
react-native-ble-plx, react-native-ble-plx,
react-native-blob-util, react-native-blob-util,
react-native-branch, react-native-branch,
react-native-siri-shortcut,
react-native-google-cast, react-native-google-cast,
react-native-pdf, react-native-pdf,
# react-native-quick-actions, # react-native-quick-actions,
+17 -2
View File
@@ -23,11 +23,14 @@ Here is a list of known packages that have a built-in Config Plugin.
- [@stripe/stripe-react-native](https://www.npmjs.com/package/@stripe/stripe-react-native) - [@stripe/stripe-react-native](https://www.npmjs.com/package/@stripe/stripe-react-native)
- [@react-native-voice/voice](https://www.npmjs.com/package/@react-native-voice/voice) - [@react-native-voice/voice](https://www.npmjs.com/package/@react-native-voice/voice)
- [react-native-imglysdk](https://www.npmjs.com/package/react-native-imglysdk) - [react-native-imglysdk](https://www.npmjs.com/package/react-native-imglysdk)
- [@viro-community/react-viro](https://github.com/virocommunity/viro) - [@viro-community/react-viro](https://github.com/virocommunity/viro) -- [Guide](https://viro-community.readme.io/docs/integrating-with-expo)
- [react-native-msal](https://www.npmjs.com/package/react-native-msal) - [react-native-msal](https://www.npmjs.com/package/react-native-msal)
- [react-native-spotlight-search](https://www.npmjs.com/package/react-native-spotlight-search) - [react-native-spotlight-search](https://www.npmjs.com/package/react-native-spotlight-search)
- [newrelic-react-native-agent](https://www.npmjs.com/package/newrelic-react-native-agent) - [newrelic-react-native-agent](https://www.npmjs.com/package/newrelic-react-native-agent)
- [react-native-videoeditorsdk](https://www.npmjs.com/package/react-native-videoeditorsdk) - [react-native-videoeditorsdk](https://www.npmjs.com/package/react-native-videoeditorsdk)
- [notifee](https://notifee.app/)
- [App Clips](https://github.com/bndkt/react-native-app-clip/)
- [iOS Safari Extensions](https://github.com/andrew-levy/react-native-safari-extension/)
### Complementary ### Complementary
@@ -39,9 +42,21 @@ More out-of-tree plugins which can be used to configure more packages.
- [config-plugin-react-native-intercom](https://www.npmjs.com/package/config-plugin-react-native-intercom) (for use with `intercom-react-native`) - [config-plugin-react-native-intercom](https://www.npmjs.com/package/config-plugin-react-native-intercom) (for use with `intercom-react-native`)
- [@allboatsrise/expo-marketingcloudsdk](https://www.npmjs.com/package/@allboatsrise/expo-marketingcloudsdk) (for use with `react-native-marketingcloudsdk`) - [@allboatsrise/expo-marketingcloudsdk](https://www.npmjs.com/package/@allboatsrise/expo-marketingcloudsdk) (for use with `react-native-marketingcloudsdk`)
- [@ouvio/react-native-background-location-plugin](https://www.npmjs.com/package/@ouvio/react-native-background-location-plugin) (for use with `react-native-background-location-plugin`) - [@ouvio/react-native-background-location-plugin](https://www.npmjs.com/package/@ouvio/react-native-background-location-plugin) (for use with `react-native-background-location-plugin`)
- [with-notifee](https://www.npmjs.com/package/with-notifee) (for use with [notifee](https://notifee.app/))
- [expo-community-flipper](https://www.npmjs.com/package/expo-community-flipper) (for use with Flipper) - [expo-community-flipper](https://www.npmjs.com/package/expo-community-flipper) (for use with Flipper)
- [expo-appcenter](https://www.npmjs.com/package/expo-appcenter) (for use with `appcenter`)
### No Plugin Required
Just install and rebuild! If a package doesn't require any futher setup then it most likely doesn't need an Expo config plugin. Most packages work without a config plugin (including packages not listed below):
- [react-native-share](https://github.com/react-native-share/react-native-share)
- [@react-native-menu/menu](https://github.com/react-native-menu/menu)
- [react-native-blurhash](https://github.com/mrousavy/react-native-blurhash)
- [react-native-app-shortcuts](https://github.com/lokyoung/react-native-app-shortcuts)
- [react-native-multiple-image-picker](https://github.com/baronha/react-native-multiple-image-picker)
- [`@shopify/flash-list`](https://github.com/Shopify/flash-list)
> Feel free to [open a PR](https://github.com/expo/config-plugins/edit/main/README.md) with missing packages.
## Contributing! ## Contributing!
@@ -0,0 +1,80 @@
node_modules/**/*
.expo/*
npm-debug.*
*.jks
*.p8
*.p12
*.key
*.mobileprovision
*.orig.*
web-build/
# macOS
.DS_Store
/artifacts
/scripts/start.command
/ios
/android
# @generated expo-cli sync-e7dcf75f4e856f7b6f3239b3f3a7dd614ee755a8
# The following patterns were generated by expo-cli
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
project.xcworkspace
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# Bundle artifacts
*.jsbundle
# CocoaPods
/ios/Pods/
# Expo
.expo/
web-build/
dist/
# @end expo-cli
Whitespace-only changes.
@@ -0,0 +1,16 @@
const path = require("path");
const folderName = path.basename(__dirname);
const cleanName = folderName.replace(/[_\s-]/g, "");
const appId = "dev.bacon." + cleanName;
module.exports = ({ config }) => {
if (!config.extra) config.extra = {};
// Expose CI env variables to the app
config.extra.CI = process.env.CI;
if (!config.ios) config.ios = {};
config.ios.bundleIdentifier = appId;
if (!config.android) config.android = {};
config.android.package = appId;
return config;
};
+14
View File
@@ -0,0 +1,14 @@
{
"expo": {
"icon": "https://icogen.vercel.app/api/icon",
"plugins": [
[
"@config-plugins/react-native-siri-shortcut",
[
"com.example.InitiateWorkout",
"com.example.FinishWorkout"
]
]
]
}
}
@@ -0,0 +1,6 @@
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
+5
View File
@@ -0,0 +1,5 @@
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);
@@ -0,0 +1,6 @@
// Learn more https://docs.expo.io/guides/customizing-metro
const { getDefaultConfig } = require("@expo/metro-config");
const config = getDefaultConfig(__dirname);
module.exports = config;
@@ -0,0 +1,25 @@
{
"name": "@config-plugins-app/react-native-siri-shortcut",
"main": "./index.js",
"version": "1.0.0",
"scripts": {
"start": "expo start --dev-client",
"ios": "expo run:ios",
"android": "expo run:android"
},
"dependencies": {
"@config-plugins/react-native-siri-shortcut": "*",
"expo": "^45.0.0",
"expo-splash-screen": "~0.15.1",
"react": "17.0.2",
"react-native": "0.68.2",
"react-native-siri-shortcut": "^3.1.0",
"expo-status-bar": "~1.3.0",
"react-dom": "17.0.2",
"react-native-web": "0.17.7"
},
"devDependencies": {
"@babel/core": "^7.12.9"
},
"private": true
}
@@ -0,0 +1,264 @@
import React, { Component } from 'react';
import {
StyleSheet,
Text,
ScrollView,
Button,
SafeAreaView,
View,
EmitterSubscription,
} from 'react-native';
import {
ShortcutOptions,
ShortcutData,
ShortcutInfo,
donateShortcut,
suggestShortcuts,
clearAllShortcuts,
clearShortcutsWithIdentifiers,
presentShortcut,
getShortcuts,
addShortcutListener,
getInitialShortcut,
AddToSiriButton,
SiriButtonStyles,
} from 'react-native-siri-shortcut';
const opts1: ShortcutOptions = {
activityType: 'com.github.gustash.SiriShortcutsModuleExample.sayHello',
title: 'Say Hi',
userInfo: {
foo: 1,
bar: 'baz',
baz: 34.5,
},
requiredUserInfoKeys: ['foo', 'bar', 'baz'],
keywords: ['kek', 'foo', 'bar'],
persistentIdentifier:
'com.github.gustash.SiriShortcutsModuleExample.sayHello',
isEligibleForSearch: true,
isEligibleForPrediction: true,
suggestedInvocationPhrase: 'Say something',
needsSave: true,
};
const opts2: ShortcutOptions = {
activityType: 'com.github.gustash.SiriShortcutsModuleExample.somethingElse',
title: 'Something Else',
persistentIdentifier: 'some.persistent.identifier',
isEligibleForSearch: true,
isEligibleForPrediction: true,
suggestedInvocationPhrase: "What's up?",
description: 'Just a random description',
};
type State = {
shortcutInfo: any | null,
shortcutActivityType: string | null,
addToSiriStyle: 0 | 1 | 2 | 3 | 4 | 5,
shortcuts: Array<ShortcutData>,
};
export default class App extends Component<void, State> {
listener: EmitterSubscription | null = null;
state: State = {
shortcutInfo: null,
shortcutActivityType: null,
addToSiriStyle: SiriButtonStyles.blackOutline,
shortcuts: [],
};
componentDidMount() {
this.handleInitialShortcut();
this.listener = addShortcutListener(this.handleSiriShortcut.bind(this));
// This will suggest these two shortcuts so that they appear
// in Settings > Siri & Search, even if they are not yet
// donated. Suitable for shortcuts that you expect the user
// may want to use. (https://developer.apple.com/documentation/sirikit/shortcut_management/suggesting_shortcuts_to_users)
suggestShortcuts([opts1, opts2]);
this.updateShortcutList();
}
componentWillUnmount() {
if (this.listener) {
this.listener.remove();
}
}
async handleInitialShortcut() {
const initialShortcut = await getInitialShortcut();
if (!initialShortcut) {
return;
}
this.handleSiriShortcut(initialShortcut);
}
handleSiriShortcut({ userInfo, activityType }: ShortcutInfo) {
this.setState({
shortcutInfo: userInfo,
shortcutActivityType: activityType,
});
}
setupShortcut1() {
donateShortcut(opts1);
}
setupShortcut2() {
donateShortcut(opts2);
}
async clearShortcut1() {
try {
await clearShortcutsWithIdentifiers([
'com.github.gustash.SiriShortcutsModuleExample.sayHello',
]);
alert('Cleared Shortcut 1');
} catch (e) {
alert("You're not running iOS 12!");
}
}
async clearShortcut2() {
try {
await clearShortcutsWithIdentifiers(['some.persistent.identifier']);
alert('Cleared Shortcut 2');
} catch (e) {
alert("You're not running iOS 12!");
}
}
async updateShortcutList() {
try {
const shortcuts = await getShortcuts();
this.setState({
shortcuts,
});
} catch (e) {
alert("You're not running iOS 12!");
}
}
async clearBothShortcuts() {
try {
await clearShortcutsWithIdentifiers([
'com.github.gustash.SiriShortcutsModuleExample.sayHello',
'some.persistent.identifier',
]);
alert('Cleared Both Shortcuts');
} catch (e) {
alert("You're not running iOS 12!");
}
}
async clearShortcuts() {
try {
await clearAllShortcuts();
alert('Deleted all the shortcuts');
} catch (e) {
alert("You're not running iOS 12!");
}
}
swapSiriButtonTheme() {
const { addToSiriStyle } = this.state;
const styles = Object.keys(SiriButtonStyles).map(
key => SiriButtonStyles[key],
);
const index = styles.findIndex(style => style === addToSiriStyle);
if (index === styles.length - 1) this.setState({ addToSiriStyle: styles[0] });
else this.setState({ addToSiriStyle: styles[index + 1] });
}
render() {
const { shortcutInfo, shortcutActivityType, addToSiriStyle, shortcuts } =
this.state;
return (
<SafeAreaView style={styles.container}>
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}>
<Text>Shortcut Activity Type: {shortcutActivityType || 'None'}</Text>
<Text>
Shortcut Info:{' '}
{shortcutInfo ? JSON.stringify(shortcutInfo) : 'No shortcut data.'}
</Text>
<Button
title="Create Shortcut 1"
onPress={this.setupShortcut1.bind(this)}
/>
<Button
title="Create Shortcut 2"
onPress={this.setupShortcut2.bind(this)}
/>
<Button
title="Clear Shortcut 1"
onPress={this.clearShortcut1.bind(this)}
/>
<Button
title="Clear Shortcut 2"
onPress={this.clearShortcut2.bind(this)}
/>
<Button
title="Clear Both Shortcuts"
onPress={this.clearBothShortcuts.bind(this)}
/>
<Button
title="Delete All Shortcuts"
onPress={this.clearShortcuts.bind(this)}
/>
<Button
title="Update list of shortcuts"
onPress={this.updateShortcutList.bind(this)}
/>
<AddToSiriButton
buttonStyle={addToSiriStyle}
onPress={() => {
presentShortcut(opts1, ({ status }) => {
console.log(`I was ${status}`);
});
}}
shortcut={opts1}
/>
<Button
title="Swap Siri Button Theme"
onPress={this.swapSiriButtonTheme.bind(this)}
/>
{shortcuts.length ? (
shortcuts.map(({ identifier, phrase, options }, i) => (
<View key={identifier}>
<Text>Shortcut {i + 1}:</Text>
<Text>Identifier - {identifier}</Text>
<Text>Phrase - {phrase}</Text>
<Text>Options - {JSON.stringify(options)}</Text>
</View>
))
) : (
<Text>No Shortcuts yet</Text>
)}
</ScrollView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
contentContainer: {
justifyContent: 'center',
alignItems: 'center',
},
});
@@ -0,0 +1,6 @@
import React from 'react';
import { View, Text } from 'react-native';
export default function App() {
return (<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}><Text>No-op on this platform</Text></View>)
}
+7
View File
@@ -1,3 +1,10 @@
### @config-plugins/ios-stickers [2.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-06-30)
### Other chores
* **deps-dev:** bump memfs in /packages/ios-stickers ([#83](https://github.com/expo/config-plugins/issues/83)) ([764a047](https://github.com/expo/config-plugins/commit/764a04710bea6e66dbc6d0065812acb1591435fb))
### @config-plugins/ios-stickers [2.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-30) ### @config-plugins/ios-stickers [2.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-30)
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@config-plugins/ios-stickers", "name": "@config-plugins/ios-stickers",
"version": "2.0.1", "version": "2.0.2",
"description": "Config plugin to auto configure iOS iMessage stickers", "description": "Config plugin to auto configure iOS iMessage stickers",
"main": "build/withStickerPack.js", "main": "build/withStickerPack.js",
"types": "build/withStickerPack.d.ts", "types": "build/withStickerPack.d.ts",
@@ -34,6 +34,6 @@
}, },
"devDependencies": { "devDependencies": {
"expo-module-scripts": "^2.0.0", "expo-module-scripts": "^2.0.0",
"memfs": "^2.15.5" "memfs": "^3.4.4"
} }
} }
@@ -1,3 +1,10 @@
### @config-plugins/react-native-ble-plx [2.0.1](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-07-25)
### Bug Fixes
* **react-native-ble-plx:** Added new Bluetooth specific permission for Android 12 (SDK 31). ([#91](https://github.com/expo/config-plugins/issues/91)) ([d3df63f](https://github.com/expo/config-plugins/commit/d3df63fbb2344251b9b371959de3ce6e4b9ab0cd))
## @config-plugins/react-native-ble-plx [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-27) ## @config-plugins/react-native-ble-plx [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-27)
+1
View File
@@ -30,6 +30,7 @@ Next, rebuild your app as described in the ["Adding custom native code"](https:/
The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used. The plugin provides props for extra customization. Every time you change the props or plugins, you'll need to rebuild (and `prebuild`) the native app. If no extra properties are added, defaults will be used.
- `isBackgroundEnabled` (_boolean_): Enable background BLE support on Android. Adds `<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>` to the `AndroidManifest.xml`. Default `false`. - `isBackgroundEnabled` (_boolean_): Enable background BLE support on Android. Adds `<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>` to the `AndroidManifest.xml`. Default `false`.
- `neverForLocation` (_boolean_): Set to true only if you can strongly assert that your app never derives physical location from Bluetooth scan results. The location permission will be still required on older Android devices. Note, that some BLE beacons are filtered from the scan results. Android SDK 31+. Default `false`. *WARNING: This parameter is experimental and BLE might not work. Make sure to test before releasing to production.*
- `modes` (_string[]_): Adds iOS `UIBackgroundModes` to the `Info.plist`. Options are: `peripheral`, and `central`. Defaults to undefined. - `modes` (_string[]_): Adds iOS `UIBackgroundModes` to the `Info.plist`. Options are: `peripheral`, and `central`. Defaults to undefined.
- `bluetoothAlwaysPermission` (_string | false_): Sets the iOS `NSBluetoothAlwaysUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`. - `bluetoothAlwaysPermission` (_string | false_): Sets the iOS `NSBluetoothAlwaysUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`.
- `bluetoothPeripheralPermission` (_string | false_): Sets the iOS `NSBluetoothPeripheralUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`. - `bluetoothPeripheralPermission` (_string | false_): Sets the iOS `NSBluetoothPeripheralUsageDescription` permission message to the `Info.plist`. Setting `false` will skip adding the permission. Defaults to `Allow $(PRODUCT_NAME) to connect to bluetooth devices`.
+1
View File
@@ -3,6 +3,7 @@ import { BackgroundMode } from "./withBLEBackgroundModes";
export { BackgroundMode }; export { BackgroundMode };
declare const _default: ConfigPlugin<void | { declare const _default: ConfigPlugin<void | {
isBackgroundEnabled?: boolean | undefined; isBackgroundEnabled?: boolean | undefined;
neverForLocation?: boolean | undefined;
modes?: BackgroundMode[] | undefined; modes?: BackgroundMode[] | undefined;
bluetoothAlwaysPermission?: string | false | undefined; bluetoothAlwaysPermission?: string | false | undefined;
bluetoothPeripheralPermission?: string | false | undefined; bluetoothPeripheralPermission?: string | false | undefined;
+7 -2
View File
@@ -11,9 +11,10 @@ const pkg = { name: "react-native-ble-plx", version: "UNVERSIONED" }; //require(
* Apply BLE configuration for Expo SDK 42 projects. * Apply BLE configuration for Expo SDK 42 projects.
*/ */
const withBLE = (config, props = {}) => { const withBLE = (config, props = {}) => {
var _a; var _a, _b;
const _props = props || {}; const _props = props || {};
const isBackgroundEnabled = (_a = _props.isBackgroundEnabled) !== null && _a !== void 0 ? _a : false; const isBackgroundEnabled = (_a = _props.isBackgroundEnabled) !== null && _a !== void 0 ? _a : false;
const neverForLocation = (_b = _props.neverForLocation) !== null && _b !== void 0 ? _b : false;
// iOS // iOS
config = withBluetoothPermissions_1.withBluetoothPermissions(config, _props); config = withBluetoothPermissions_1.withBluetoothPermissions(config, _props);
config = withBLEBackgroundModes_1.withBLEBackgroundModes(config, _props.modes || []); config = withBLEBackgroundModes_1.withBLEBackgroundModes(config, _props.modes || []);
@@ -21,8 +22,12 @@ const withBLE = (config, props = {}) => {
config = config_plugins_1.AndroidConfig.Permissions.withPermissions(config, [ config = config_plugins_1.AndroidConfig.Permissions.withPermissions(config, [
"android.permission.BLUETOOTH", "android.permission.BLUETOOTH",
"android.permission.BLUETOOTH_ADMIN", "android.permission.BLUETOOTH_ADMIN",
"android.permission.BLUETOOTH_CONNECT", // since Android SDK 31
]); ]);
config = withBLEAndroidManifest_1.withBLEAndroidManifest(config, { isBackgroundEnabled }); config = withBLEAndroidManifest_1.withBLEAndroidManifest(config, {
isBackgroundEnabled,
neverForLocation,
});
return config; return config;
}; };
exports.default = config_plugins_1.createRunOncePlugin(withBLE, pkg.name, pkg.version); exports.default = config_plugins_1.createRunOncePlugin(withBLE, pkg.name, pkg.version);
+21 -3
View File
@@ -1,17 +1,35 @@
import { ConfigPlugin, AndroidConfig } from "@expo/config-plugins"; import { ConfigPlugin, AndroidConfig } from "@expo/config-plugins";
declare type InnerManifest = AndroidConfig.Manifest.AndroidManifest["manifest"]; declare type InnerManifest = AndroidConfig.Manifest.AndroidManifest["manifest"];
declare type ManifestPermission = InnerManifest["permission"]; declare type ManifestPermission = InnerManifest["permission"];
declare type ExtraTools = {
"tools:targetApi"?: string;
};
declare type ManifestUsesPermissionWithExtraTools = {
$: AndroidConfig.Manifest.ManifestUsesPermission["$"] & ExtraTools;
};
declare type AndroidManifest = { declare type AndroidManifest = {
manifest: InnerManifest & { manifest: InnerManifest & {
permission?: ManifestPermission; permission?: ManifestPermission;
"uses-permission"?: InnerManifest["uses-permission"]; "uses-permission"?: ManifestUsesPermissionWithExtraTools[];
"uses-permission-sdk-23"?: InnerManifest["uses-permission"]; "uses-permission-sdk-23"?: ManifestUsesPermissionWithExtraTools[];
"uses-feature"?: InnerManifest["uses-feature"]; "uses-feature"?: InnerManifest["uses-feature"];
}; };
}; };
export declare const withBLEAndroidManifest: ConfigPlugin<{ export declare const withBLEAndroidManifest: ConfigPlugin<{
isBackgroundEnabled: boolean; isBackgroundEnabled: boolean;
neverForLocation: boolean;
}>; }>;
export declare function addFineControlPermissionToManifest(androidManifest: AndroidManifest): AndroidManifest; /**
* Add location permissions
* - 'android.permission.ACCESS_COARSE_LOCATION' for Android SDK 28 (Android 9) and lower
* - 'android.permission.ACCESS_FINE_LOCATION' for Android SDK 29 (Android 10) and higher.
* From Android SDK 31 (Android 12) it might not be required if BLE is not used for location.
*/
export declare function addLocationPermissionToManifest(androidManifest: AndroidManifest, neverForLocationSinceSdk31: boolean): AndroidManifest;
/**
* Add 'android.permission.BLUETOOTH_SCAN'.
* Required since Android SDK 31 (Android 12).
*/
export declare function addScanPermissionToManifest(androidManifest: AndroidManifest, neverForLocation: boolean): AndroidManifest;
export declare function addBLEHardwareFeatureToManifest(androidManifest: AndroidConfig.Manifest.AndroidManifest): AndroidConfig.Manifest.AndroidManifest; export declare function addBLEHardwareFeatureToManifest(androidManifest: AndroidConfig.Manifest.AndroidManifest): AndroidConfig.Manifest.AndroidManifest;
export {}; export {};
+53 -8
View File
@@ -1,10 +1,11 @@
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.addBLEHardwareFeatureToManifest = exports.addFineControlPermissionToManifest = exports.withBLEAndroidManifest = void 0; exports.addBLEHardwareFeatureToManifest = exports.addScanPermissionToManifest = exports.addLocationPermissionToManifest = exports.withBLEAndroidManifest = void 0;
const config_plugins_1 = require("@expo/config-plugins"); const config_plugins_1 = require("@expo/config-plugins");
const withBLEAndroidManifest = (config, { isBackgroundEnabled }) => { const withBLEAndroidManifest = (config, { isBackgroundEnabled, neverForLocation }) => {
return config_plugins_1.withAndroidManifest(config, (config) => { return config_plugins_1.withAndroidManifest(config, (config) => {
config.modResults = addFineControlPermissionToManifest(config.modResults); config.modResults = addLocationPermissionToManifest(config.modResults, neverForLocation);
config.modResults = addScanPermissionToManifest(config.modResults, neverForLocation);
if (isBackgroundEnabled) { if (isBackgroundEnabled) {
config.modResults = addBLEHardwareFeatureToManifest(config.modResults); config.modResults = addBLEHardwareFeatureToManifest(config.modResults);
} }
@@ -12,22 +13,66 @@ const withBLEAndroidManifest = (config, { isBackgroundEnabled }) => {
}); });
}; };
exports.withBLEAndroidManifest = withBLEAndroidManifest; exports.withBLEAndroidManifest = withBLEAndroidManifest;
function addFineControlPermissionToManifest(androidManifest) { /**
var _a; * Add location permissions
// Add `<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>` to the AndroidManifest.xml * - 'android.permission.ACCESS_COARSE_LOCATION' for Android SDK 28 (Android 9) and lower
* - 'android.permission.ACCESS_FINE_LOCATION' for Android SDK 29 (Android 10) and higher.
* From Android SDK 31 (Android 12) it might not be required if BLE is not used for location.
*/
function addLocationPermissionToManifest(androidManifest, neverForLocationSinceSdk31) {
if (!Array.isArray(androidManifest.manifest["uses-permission-sdk-23"])) { if (!Array.isArray(androidManifest.manifest["uses-permission-sdk-23"])) {
androidManifest.manifest["uses-permission-sdk-23"] = []; androidManifest.manifest["uses-permission-sdk-23"] = [];
} }
const optMaxSdkVersion = neverForLocationSinceSdk31
? {
"android:maxSdkVersion": "30",
}
: {};
if (!androidManifest.manifest["uses-permission-sdk-23"].find((item) => item.$["android:name"] === "android.permission.ACCESS_COARSE_LOCATION")) {
androidManifest.manifest["uses-permission-sdk-23"].push({
$: {
"android:name": "android.permission.ACCESS_COARSE_LOCATION",
...optMaxSdkVersion,
},
});
}
if (!androidManifest.manifest["uses-permission-sdk-23"].find((item) => item.$["android:name"] === "android.permission.ACCESS_FINE_LOCATION")) { if (!androidManifest.manifest["uses-permission-sdk-23"].find((item) => item.$["android:name"] === "android.permission.ACCESS_FINE_LOCATION")) {
(_a = androidManifest.manifest["uses-permission-sdk-23"]) === null || _a === void 0 ? void 0 : _a.push({ androidManifest.manifest["uses-permission-sdk-23"].push({
$: { $: {
"android:name": "android.permission.ACCESS_FINE_LOCATION", "android:name": "android.permission.ACCESS_FINE_LOCATION",
...optMaxSdkVersion,
}, },
}); });
} }
return androidManifest; return androidManifest;
} }
exports.addFineControlPermissionToManifest = addFineControlPermissionToManifest; exports.addLocationPermissionToManifest = addLocationPermissionToManifest;
/**
* Add 'android.permission.BLUETOOTH_SCAN'.
* Required since Android SDK 31 (Android 12).
*/
function addScanPermissionToManifest(androidManifest, neverForLocation) {
var _a;
if (!Array.isArray(androidManifest.manifest["uses-permission"])) {
androidManifest.manifest["uses-permission"] = [];
}
if (!androidManifest.manifest["uses-permission"].find((item) => item.$["android:name"] === "android.permission.BLUETOOTH_SCAN")) {
config_plugins_1.AndroidConfig.Manifest.ensureToolsAvailable(androidManifest);
(_a = androidManifest.manifest["uses-permission"]) === null || _a === void 0 ? void 0 : _a.push({
$: {
"android:name": "android.permission.BLUETOOTH_SCAN",
...(neverForLocation
? {
"android:usesPermissionFlags": "neverForLocation",
}
: {}),
"tools:targetApi": "31",
},
});
}
return androidManifest;
}
exports.addScanPermissionToManifest = addScanPermissionToManifest;
// Add this line if your application always requires BLE. More info can be found on: https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#permissions // Add this line if your application always requires BLE. More info can be found on: https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#permissions
function addBLEHardwareFeatureToManifest(androidManifest) { function addBLEHardwareFeatureToManifest(androidManifest) {
var _a; var _a;
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@config-plugins/react-native-ble-plx", "name": "@config-plugins/react-native-ble-plx",
"version": "2.0.0", "version": "2.0.1",
"description": "Config plugin to auto configure react-native-ble-plx on prebuild", "description": "Config plugin to auto configure react-native-ble-plx on prebuild",
"main": "build/withBLE.js", "main": "build/withBLE.js",
"types": "build/withBLE.d.ts", "types": "build/withBLE.d.ts",
@@ -2,31 +2,98 @@ import { AndroidConfig, XML } from "@expo/config-plugins";
import { resolve } from "path"; import { resolve } from "path";
import { import {
addLocationPermissionToManifest,
addScanPermissionToManifest,
addBLEHardwareFeatureToManifest, addBLEHardwareFeatureToManifest,
addFineControlPermissionToManifest,
} from "../withBLEAndroidManifest"; } from "../withBLEAndroidManifest";
const { readAndroidManifestAsync } = AndroidConfig.Manifest; const { readAndroidManifestAsync } = AndroidConfig.Manifest;
const sampleManifestPath = resolve(__dirname, "fixtures/AndroidManifest.xml"); const sampleManifestPath = resolve(__dirname, "fixtures/AndroidManifest.xml");
describe("addFineControlPermissionToManifest", () => { describe("addLocationPermissionToManifest", () => {
it(`adds element`, async () => { it(`adds elements`, async () => {
let androidManifest = await readAndroidManifestAsync(sampleManifestPath); let androidManifest = await readAndroidManifestAsync(sampleManifestPath);
androidManifest = await addFineControlPermissionToManifest(androidManifest); androidManifest = addLocationPermissionToManifest(androidManifest, false);
expect(androidManifest.manifest["uses-permission-sdk-23"]).toStrictEqual([ expect(androidManifest.manifest["uses-permission-sdk-23"]).toContainEqual({
{ $: { "android:name": "android.permission.ACCESS_FINE_LOCATION" } }, $: {
]); "android:name": "android.permission.ACCESS_COARSE_LOCATION",
},
});
expect(androidManifest.manifest["uses-permission-sdk-23"]).toContainEqual({
$: {
"android:name": "android.permission.ACCESS_FINE_LOCATION",
},
});
// Sanity // Sanity
expect(XML.format(androidManifest)).toMatch(
/<uses-permission-sdk-23 android:name="android\.permission\.ACCESS_COARSE_LOCATION"\/>/
);
expect(XML.format(androidManifest)).toMatch( expect(XML.format(androidManifest)).toMatch(
/<uses-permission-sdk-23 android:name="android\.permission\.ACCESS_FINE_LOCATION"\/>/ /<uses-permission-sdk-23 android:name="android\.permission\.ACCESS_FINE_LOCATION"\/>/
); );
}); });
it(`adds elements with SDK limit`, async () => {
let androidManifest = await readAndroidManifestAsync(sampleManifestPath);
androidManifest = addLocationPermissionToManifest(androidManifest, true);
expect(androidManifest.manifest["uses-permission-sdk-23"]).toContainEqual({
$: {
"android:name": "android.permission.ACCESS_COARSE_LOCATION",
"android:maxSdkVersion": "30",
},
});
expect(androidManifest.manifest["uses-permission-sdk-23"]).toContainEqual({
$: {
"android:name": "android.permission.ACCESS_FINE_LOCATION",
"android:maxSdkVersion": "30",
},
});
// Sanity
expect(XML.format(androidManifest)).toMatch(
/<uses-permission-sdk-23 android:name="android\.permission\.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30"\/>/
);
expect(XML.format(androidManifest)).toMatch(
/<uses-permission-sdk-23 android:name="android\.permission\.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"\/>/
);
});
}); });
describe("addScanPermissionToManifest", () => {
it(`adds element`, async () => {
let androidManifest = await readAndroidManifestAsync(sampleManifestPath);
androidManifest = addScanPermissionToManifest(androidManifest, false);
expect(androidManifest.manifest["uses-permission"]).toContainEqual({
$: {
"android:name": "android.permission.BLUETOOTH_SCAN",
"tools:targetApi": "31",
},
});
// Sanity
expect(XML.format(androidManifest)).toMatch(
/<uses-permission android:name="android\.permission\.BLUETOOTH_SCAN" tools:targetApi="31"\/>/
);
});
it(`adds element with 'neverForLocation' attribute`, async () => {
let androidManifest = await readAndroidManifestAsync(sampleManifestPath);
androidManifest = addScanPermissionToManifest(androidManifest, true);
expect(androidManifest.manifest["uses-permission"]).toContainEqual({
$: {
"android:name": "android.permission.BLUETOOTH_SCAN",
"android:usesPermissionFlags": "neverForLocation",
"tools:targetApi": "31",
},
});
// Sanity
expect(XML.format(androidManifest)).toMatch(
/<uses-permission android:name="android\.permission\.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" tools:targetApi="31"\/>/
);
});
});
describe("addBLEHardwareFeatureToManifest", () => { describe("addBLEHardwareFeatureToManifest", () => {
it(`adds element`, async () => { it(`adds element`, async () => {
let androidManifest = await readAndroidManifestAsync(sampleManifestPath); let androidManifest = await readAndroidManifestAsync(sampleManifestPath);
androidManifest = await addBLEHardwareFeatureToManifest(androidManifest); androidManifest = addBLEHardwareFeatureToManifest(androidManifest);
expect(androidManifest.manifest["uses-feature"]).toStrictEqual([ expect(androidManifest.manifest["uses-feature"]).toStrictEqual([
{ {
+7 -1
View File
@@ -18,12 +18,14 @@ const pkg = { name: "react-native-ble-plx", version: "UNVERSIONED" }; //require(
*/ */
const withBLE: ConfigPlugin<{ const withBLE: ConfigPlugin<{
isBackgroundEnabled?: boolean; isBackgroundEnabled?: boolean;
neverForLocation?: boolean;
modes?: BackgroundMode[]; modes?: BackgroundMode[];
bluetoothAlwaysPermission?: string | false; bluetoothAlwaysPermission?: string | false;
bluetoothPeripheralPermission?: string | false; bluetoothPeripheralPermission?: string | false;
} | void> = (config, props = {}) => { } | void> = (config, props = {}) => {
const _props = props || {}; const _props = props || {};
const isBackgroundEnabled = _props.isBackgroundEnabled ?? false; const isBackgroundEnabled = _props.isBackgroundEnabled ?? false;
const neverForLocation = _props.neverForLocation ?? false;
// iOS // iOS
config = withBluetoothPermissions(config, _props); config = withBluetoothPermissions(config, _props);
@@ -33,8 +35,12 @@ const withBLE: ConfigPlugin<{
config = AndroidConfig.Permissions.withPermissions(config, [ config = AndroidConfig.Permissions.withPermissions(config, [
"android.permission.BLUETOOTH", "android.permission.BLUETOOTH",
"android.permission.BLUETOOTH_ADMIN", "android.permission.BLUETOOTH_ADMIN",
"android.permission.BLUETOOTH_CONNECT", // since Android SDK 31
]); ]);
config = withBLEAndroidManifest(config, { isBackgroundEnabled }); config = withBLEAndroidManifest(config, {
isBackgroundEnabled,
neverForLocation,
});
return config; return config;
}; };
@@ -8,20 +8,38 @@ type InnerManifest = AndroidConfig.Manifest.AndroidManifest["manifest"];
type ManifestPermission = InnerManifest["permission"]; type ManifestPermission = InnerManifest["permission"];
// TODO: add to `AndroidManifestAttributes` in @expo/config-plugins
type ExtraTools = {
// https://developer.android.com/studio/write/tool-attributes#toolstargetapi
"tools:targetApi"?: string;
};
type ManifestUsesPermissionWithExtraTools = {
$: AndroidConfig.Manifest.ManifestUsesPermission["$"] & ExtraTools;
};
type AndroidManifest = { type AndroidManifest = {
manifest: InnerManifest & { manifest: InnerManifest & {
permission?: ManifestPermission; permission?: ManifestPermission;
"uses-permission"?: InnerManifest["uses-permission"]; "uses-permission"?: ManifestUsesPermissionWithExtraTools[];
"uses-permission-sdk-23"?: InnerManifest["uses-permission"]; "uses-permission-sdk-23"?: ManifestUsesPermissionWithExtraTools[];
"uses-feature"?: InnerManifest["uses-feature"]; "uses-feature"?: InnerManifest["uses-feature"];
}; };
}; };
export const withBLEAndroidManifest: ConfigPlugin<{ export const withBLEAndroidManifest: ConfigPlugin<{
isBackgroundEnabled: boolean; isBackgroundEnabled: boolean;
}> = (config, { isBackgroundEnabled }) => { neverForLocation: boolean;
}> = (config, { isBackgroundEnabled, neverForLocation }) => {
return withAndroidManifest(config, (config) => { return withAndroidManifest(config, (config) => {
config.modResults = addFineControlPermissionToManifest(config.modResults); config.modResults = addLocationPermissionToManifest(
config.modResults,
neverForLocation
);
config.modResults = addScanPermissionToManifest(
config.modResults,
neverForLocation
);
if (isBackgroundEnabled) { if (isBackgroundEnabled) {
config.modResults = addBLEHardwareFeatureToManifest(config.modResults); config.modResults = addBLEHardwareFeatureToManifest(config.modResults);
} }
@@ -29,23 +47,84 @@ export const withBLEAndroidManifest: ConfigPlugin<{
}); });
}; };
export function addFineControlPermissionToManifest( /**
androidManifest: AndroidManifest * Add location permissions
* - 'android.permission.ACCESS_COARSE_LOCATION' for Android SDK 28 (Android 9) and lower
* - 'android.permission.ACCESS_FINE_LOCATION' for Android SDK 29 (Android 10) and higher.
* From Android SDK 31 (Android 12) it might not be required if BLE is not used for location.
*/
export function addLocationPermissionToManifest(
androidManifest: AndroidManifest,
neverForLocationSinceSdk31: boolean
) { ) {
// Add `<uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>` to the AndroidManifest.xml
if (!Array.isArray(androidManifest.manifest["uses-permission-sdk-23"])) { if (!Array.isArray(androidManifest.manifest["uses-permission-sdk-23"])) {
androidManifest.manifest["uses-permission-sdk-23"] = []; androidManifest.manifest["uses-permission-sdk-23"] = [];
} }
const optMaxSdkVersion = neverForLocationSinceSdk31
? {
"android:maxSdkVersion": "30",
}
: {};
if (
!androidManifest.manifest["uses-permission-sdk-23"].find(
(item) =>
item.$["android:name"] === "android.permission.ACCESS_COARSE_LOCATION"
)
) {
androidManifest.manifest["uses-permission-sdk-23"].push({
$: {
"android:name": "android.permission.ACCESS_COARSE_LOCATION",
...optMaxSdkVersion,
},
});
}
if ( if (
!androidManifest.manifest["uses-permission-sdk-23"].find( !androidManifest.manifest["uses-permission-sdk-23"].find(
(item) => (item) =>
item.$["android:name"] === "android.permission.ACCESS_FINE_LOCATION" item.$["android:name"] === "android.permission.ACCESS_FINE_LOCATION"
) )
) { ) {
androidManifest.manifest["uses-permission-sdk-23"]?.push({ androidManifest.manifest["uses-permission-sdk-23"].push({
$: { $: {
"android:name": "android.permission.ACCESS_FINE_LOCATION", "android:name": "android.permission.ACCESS_FINE_LOCATION",
...optMaxSdkVersion,
},
});
}
return androidManifest;
}
/**
* Add 'android.permission.BLUETOOTH_SCAN'.
* Required since Android SDK 31 (Android 12).
*/
export function addScanPermissionToManifest(
androidManifest: AndroidManifest,
neverForLocation: boolean
) {
if (!Array.isArray(androidManifest.manifest["uses-permission"])) {
androidManifest.manifest["uses-permission"] = [];
}
if (
!androidManifest.manifest["uses-permission"].find(
(item) => item.$["android:name"] === "android.permission.BLUETOOTH_SCAN"
)
) {
AndroidConfig.Manifest.ensureToolsAvailable(androidManifest);
androidManifest.manifest["uses-permission"]?.push({
$: {
"android:name": "android.permission.BLUETOOTH_SCAN",
...(neverForLocation
? {
"android:usesPermissionFlags": "neverForLocation",
}
: {}),
"tools:targetApi": "31",
}, },
}); });
} }
@@ -1,3 +1,19 @@
## @config-plugins/react-native-callkeep [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-07-25)
### ⚠ BREAKING CHANGES
* add SDK 45 support (#79)
### Features
* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
### Other chores
* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
### @config-plugins/react-native-callkeep [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-03-22) ### @config-plugins/react-native-callkeep [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-03-22)
@@ -1,3 +1,19 @@
## @config-plugins/react-native-dynamic-app-icon [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-06-14)
### ⚠ BREAKING CHANGES
* add SDK 45 support (#79)
### Features
* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
### Other chores
* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
### @config-plugins/react-native-dynamic-app-icon [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-12) ### @config-plugins/react-native-dynamic-app-icon [1.0.3](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-05-12)
+16
View File
@@ -1,3 +1,19 @@
## @config-plugins/react-native-pdf [2.0.0](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-08-04)
### ⚠ BREAKING CHANGES
* add SDK 45 support (#79)
### Features
* add SDK 45 support ([#79](https://github.com/expo/config-plugins/issues/79)) ([96c72dd](https://github.com/expo/config-plugins/commit/96c72dda469ace2b9eafd38ba4d21f1bcd2e3cdf))
### Other chores
* publish packages [no-ci] ([0c7b413](https://github.com/expo/config-plugins/commit/0c7b413a765e4b1ff92b9e3edc2b62077c41ce46))
### @config-plugins/react-native-pdf [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-03-22) ### @config-plugins/react-native-pdf [1.0.2](https://github.com/expo/config-plugins/compare/@config-plugins/[email protected]...@config-plugins/[email protected]) (2022-03-22)
@@ -0,0 +1,11 @@
## @config-plugins/react-native-siri-shortcut 1.0.0 (2022-07-12)
### Features
* **siri-shortcut:** Add config plugin ([#86](https://github.com/expo/config-plugins/issues/86)) ([226b2a6](https://github.com/expo/config-plugins/commit/226b2a6412ad3fe75c98952831fab5a63254d19f))
### Other chores
* **react-native-siri-shortcut:** add tests ([#88](https://github.com/expo/config-plugins/issues/88)) ([994fadc](https://github.com/expo/config-plugins/commit/994fadc8ddf9ee858f2ccb7d544674f107f7f9ad))
@@ -0,0 +1,6 @@
import { ConfigPlugin } from "@expo/config-plugins";
import { MergeResults } from "@expo/config-plugins/build/utils/generateCode";
export declare function addSiriShortcutAppDelegateImport(src: string): MergeResults;
export declare function addSiriShortcutAppDelegateInit(src: string): MergeResults;
declare const _default: ConfigPlugin<void | string[]>;
export default _default;
@@ -0,0 +1,88 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.addSiriShortcutAppDelegateInit = exports.addSiriShortcutAppDelegateImport = void 0;
const config_plugins_1 = require("@expo/config-plugins");
const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
/**
* Apply react-native-siri-shortcut configuration for Expo SDK 44 projects.
*/
const withReactNativeSiriShortcut = (config, activityTypes) => {
withSiriShortcutAppDelegate(config);
withSiriEntitlements(config);
const items = activityTypes || [];
if (!Array.isArray(items) || !items.length) {
return config;
}
return withReactNativeSiriShortcutInfoPlist(config, items);
};
const withReactNativeSiriShortcutInfoPlist = (config, activityTypes) => {
return config_plugins_1.withInfoPlist(config, (config) => {
config.modResults.NSUserActivityTypes = activityTypes;
return config;
});
};
function addSiriShortcutAppDelegateImport(src) {
return generateCode_1.mergeContents({
tag: "react-native-siri-shortcut",
src,
newSrc: "#import <RNSiriShortcuts/RNSiriShortcuts.h>",
anchor: /#import "AppDelegate\.h"/,
offset: 1,
comment: "//",
});
}
exports.addSiriShortcutAppDelegateImport = addSiriShortcutAppDelegateImport;
function addSiriShortcutAppDelegateInit(src) {
return generateCode_1.mergeContents({
tag: "react-native-siri-shortcut-delegate",
src,
newSrc: [
" BOOL shortcutResult = [RNSSSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];",
" if (shortcutResult) {",
" return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || shortcutResult;",
" }",
].join("\n"),
anchor: / return \[super application:application continueUserActivity:userActivity restorationHandler:restorationHandler\] \|\| result;/,
offset: -1,
comment: "//",
});
}
exports.addSiriShortcutAppDelegateInit = addSiriShortcutAppDelegateInit;
/** Append the siri entitlement on iOS */
const withSiriEntitlements = (config) => {
return config_plugins_1.withEntitlementsPlist(config, (config) => {
config.modResults["com.apple.developer.siri"] = true;
return config;
});
};
const withSiriShortcutAppDelegate = (config) => {
return config_plugins_1.withAppDelegate(config, (config) => {
if (["objc", "objcpp"].includes(config.modResults.language)) {
try {
config.modResults.contents = addSiriShortcutAppDelegateImport(config.modResults.contents).contents;
config.modResults.contents = addSiriShortcutAppDelegateInit(config.modResults.contents).contents;
}
catch (error) {
if (error.code === "ERR_NO_MATCH") {
throw new Error(`Cannot add Siri Shortcut to the project's AppDelegate because it's malformed. Please report this with a copy of your project AppDelegate.`);
}
throw error;
}
}
else {
throw new Error("Cannot setup Siri Shortcut because the AppDelegate is not Objective C");
}
return config;
});
};
const pkg = {
// Prevent this plugin from being run more than once.
// This pattern enables users to safely migrate off of this
// out-of-tree `@config-plugins/react-native-siri-shortcut` to a future
// upstream plugin in `react-native-siri-shortcut`
name: "react-native-siri-shortcut",
// Indicates that this plugin is dangerously linked to a module,
// and might not work with the latest version of that module.
version: "UNVERSIONED",
};
exports.default = config_plugins_1.createRunOncePlugin(withReactNativeSiriShortcut, pkg.name, pkg.version);
@@ -0,0 +1 @@
module.exports = require('expo-module-scripts/jest-preset-plugin');
@@ -1,6 +1,6 @@
{ {
"name": "@config-plugins/react-native-siri-shortcut", "name": "@config-plugins/react-native-siri-shortcut",
"version": "0.0.0", "version": "1.0.0",
"description": "Config plugin for react-native-siri-shortcut package", "description": "Config plugin for react-native-siri-shortcut package",
"main": "build/withReactNativeSiriShortcut.js", "main": "build/withReactNativeSiriShortcut.js",
"types": "build/withReactNativeSiriShortcut.d.ts", "types": "build/withReactNativeSiriShortcut.d.ts",
@@ -35,5 +35,6 @@
}, },
"devDependencies": { "devDependencies": {
"expo-module-scripts": "^2.0.0" "expo-module-scripts": "^2.0.0"
} },
"upstreamPackage": "react-native-siri-shortcut"
} }
@@ -0,0 +1,306 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`addSiriShortcutAppDelegateImport adds import to Expo Modules AppDelegate 1`] = `
"
#import \\"AppDelegate.h\\"
// @generated begin react-native-siri-shortcut - expo prebuild (DO NOT MODIFY) sync-34828decdfd158f5b96fe11a1e590a684e296e0e
#import <RNSiriShortcuts/RNSiriShortcuts.h>
// @generated end react-native-siri-shortcut
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTConvert.h>
#import <React/RCTAppSetupUtils.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert(\\"ReactNativeConfig\\", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@\\"main\\" initialProperties:nil];
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
{
// If you'd like to export some custom RCTBridgeModules, add them here!
return @[];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\\"index\\"];
#else
return [[NSBundle mainBundle] URLForResource:@\\"main\\" withExtension:@\\"jsbundle\\"];
#endif
}
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}
// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end
"
`;
exports[`addSiriShortcutAppDelegateInit adds init to Expo Modules AppDelegate 1`] = `
"
#import \\"AppDelegate.h\\"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTConvert.h>
#import <React/RCTAppSetupUtils.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert(\\"ReactNativeConfig\\", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@\\"main\\" initialProperties:nil];
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
{
// If you'd like to export some custom RCTBridgeModules, add them here!
return @[];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@\\"index\\"];
#else
return [[NSBundle mainBundle] URLForResource:@\\"main\\" withExtension:@\\"jsbundle\\"];
#endif
}
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}
// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
// @generated begin react-native-siri-shortcut-delegate - expo prebuild (DO NOT MODIFY) sync-291450a04ff243636b0bd0aef4a614f7218690b5
BOOL shortcutResult = [RNSSSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
if (shortcutResult) {
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || shortcutResult;
}
// @generated end react-native-siri-shortcut-delegate
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end
"
`;
@@ -0,0 +1,146 @@
// SDK +45: https://github.com/expo/expo/blob/sdk-45/templates/expo-template-bare-minimum/ios/HelloWorld/AppDelegate.m
export const ExpoModulesAppDelegate = `
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTConvert.h>
#import <React/RCTAppSetupUtils.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
{
// If you'd like to export some custom RCTBridgeModules, add them here!
return @[];
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
}
// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
BOOL result = [RCTLinkingManager application:application continueUserActivity:userActivity restorationHandler:restorationHandler];
return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || result;
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
return [super application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
return [super application:application didFailToRegisterForRemoteNotificationsWithError:error];
}
// Explicitly define remote notification delegates to ensure compatibility with some third-party libraries
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
return [super application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end
`;
@@ -0,0 +1,42 @@
import {
addSiriShortcutAppDelegateImport,
addSiriShortcutAppDelegateInit,
} from "../withReactNativeSiriShortcut";
import { ExpoModulesAppDelegate } from "./fixtures/AppDelegate";
describe(addSiriShortcutAppDelegateImport, () => {
it(`adds import to Expo Modules AppDelegate`, () => {
const results = addSiriShortcutAppDelegateImport(ExpoModulesAppDelegate);
// matches a static snapshot
expect(results.contents).toMatchSnapshot();
expect(results.contents).toMatch(/react-native-siri-shortcut/);
expect(results.contents).toMatch(/RNSiriShortcuts\/RNSiriShortcuts\.h/);
// did add new content
expect(results.didMerge).toBe(true);
// didn't remove old content
expect(results.didClear).toBe(false);
});
it(`fails to add to a malformed app delegate`, () => {
expect(() => addSiriShortcutAppDelegateImport(`foobar`)).toThrow(/foobar/);
});
});
describe(addSiriShortcutAppDelegateInit, () => {
it(`adds init to Expo Modules AppDelegate`, () => {
const results = addSiriShortcutAppDelegateInit(ExpoModulesAppDelegate);
// matches a static snapshot
expect(results.contents).toMatchSnapshot();
expect(results.contents).toMatch(/react-native-siri-shortcut-delegate/);
expect(results.contents).toMatch(
/RNSSSiriShortcuts application:application/
);
// did add new content
expect(results.didMerge).toBe(true);
// didn't remove old content
expect(results.didClear).toBe(false);
});
it(`fails to add to a malformed app delegate`, () => {
expect(() => addSiriShortcutAppDelegateInit(`foobar`)).toThrow(/foobar/);
});
});
@@ -17,16 +17,23 @@ const withReactNativeSiriShortcut: ConfigPlugin<void | string[]> = (
config, config,
activityTypes activityTypes
) => { ) => {
config = withSiriShortcutAppDelegate(config); withSiriShortcutAppDelegate(config);
withSiriEntitlements(config);
const items = activityTypes || []; const items = activityTypes || [];
if (!Array.isArray(items) || !items.length) { if (!Array.isArray(items) || !items.length) {
return config; return config;
} }
return withReactNativeSiriShortcutInfoPlist(config, items);
};
const withReactNativeSiriShortcutInfoPlist: ConfigPlugin<string[]> = (
config,
activityTypes
) => {
return withInfoPlist(config, (config) => { return withInfoPlist(config, (config) => {
config.modResults.NSUserActivityTypes = items; config.modResults.NSUserActivityTypes = activityTypes;
return config; return config;
}); });
}; };
@@ -43,25 +50,23 @@ export function addSiriShortcutAppDelegateImport(src: string): MergeResults {
} }
export function addSiriShortcutAppDelegateInit(src: string): MergeResults { export function addSiriShortcutAppDelegateInit(src: string): MergeResults {
const newSrc = [];
newSrc.push(
" BOOL shortcutResult = [RNSSSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];",
" if (shortcutResult) {",
" return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || shortcutResult;",
" }"
);
console.log(src);
return mergeContents({ return mergeContents({
tag: "react-native-siri-shortcut-delegate", tag: "react-native-siri-shortcut-delegate",
src, src,
newSrc: newSrc.join("\n"), newSrc: [
" BOOL shortcutResult = [RNSSSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];",
" if (shortcutResult) {",
" return [super application:application continueUserActivity:userActivity restorationHandler:restorationHandler] || shortcutResult;",
" }",
].join("\n"),
anchor: anchor:
/ return \[super application:application continueUserActivity:userActivity restorationHandler:restorationHandler\] \|\| result;/, / return \[super application:application continueUserActivity:userActivity restorationHandler:restorationHandler\] \|\| result;/,
offset: -1, offset: -1,
comment: "//", comment: "//",
}); });
} }
/** Append the siri entitlement on iOS */
const withSiriEntitlements: ConfigPlugin = (config) => { const withSiriEntitlements: ConfigPlugin = (config) => {
return withEntitlementsPlist(config, (config) => { return withEntitlementsPlist(config, (config) => {
config.modResults["com.apple.developer.siri"] = true; config.modResults["com.apple.developer.siri"] = true;
@@ -70,7 +75,7 @@ const withSiriEntitlements: ConfigPlugin = (config) => {
}; };
const withSiriShortcutAppDelegate: ConfigPlugin = (config) => { const withSiriShortcutAppDelegate: ConfigPlugin = (config) => {
let cfg = withAppDelegate(config, (config) => { return withAppDelegate(config, (config) => {
if (["objc", "objcpp"].includes(config.modResults.language)) { if (["objc", "objcpp"].includes(config.modResults.language)) {
try { try {
config.modResults.contents = addSiriShortcutAppDelegateImport( config.modResults.contents = addSiriShortcutAppDelegateImport(
@@ -94,9 +99,6 @@ const withSiriShortcutAppDelegate: ConfigPlugin = (config) => {
} }
return config; return config;
}); });
cfg = withSiriEntitlements(cfg);
return cfg;
}; };
const pkg = { const pkg = {
+5 -2
View File
@@ -16941,6 +16941,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.2.4.tgz#4df42819759c4d3c74252c8678c2772cfa2271a6" resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.2.4.tgz#4df42819759c4d3c74252c8678c2772cfa2271a6"
integrity sha512-OOX+W2G4YYufvryonn6Kw6YnyT8ZThkxPHZBD04NLHaZmicUaaDVII/PZ3M5fD1o5N62+T+8K4bCS5Un2ggvkA== integrity sha512-OOX+W2G4YYufvryonn6Kw6YnyT8ZThkxPHZBD04NLHaZmicUaaDVII/PZ3M5fD1o5N62+T+8K4bCS5Un2ggvkA==
react-native-siri-shortcut@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/react-native-siri-shortcut/-/react-native-siri-shortcut-3.1.0.tgz#920adf41eb6c72c93ef8571259c8d35358e50e71"
integrity sha512-MM0f7HS3ADU2gUh0Q6n935uhdfA3KgjpN8hEEhf2RSf4azcRNh8zNMwZD08pGSrP9/JYj1kYndQ0oytpwPyk/A==
[email protected]: [email protected]:
version "0.17.7" version "0.17.7"
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.17.7.tgz#038899dbc94467a0ca0be214b88a30e0c117b176" resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.17.7.tgz#038899dbc94467a0ca0be214b88a30e0c117b176"
@@ -20118,10 +20123,8 @@ watchpack@^1.6.1:
resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453"
integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==
dependencies: dependencies:
chokidar "^3.4.1"
graceful-fs "^4.1.2" graceful-fs "^4.1.2"
neo-async "^2.5.0" neo-async "^2.5.0"
watchpack-chokidar2 "^2.0.1"
optionalDependencies: optionalDependencies:
chokidar "^3.4.1" chokidar "^3.4.1"
watchpack-chokidar2 "^2.0.1" watchpack-chokidar2 "^2.0.1"