@trentrand/react-native-app-clip 0.6.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -0
- package/app.plugin.js +1 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.d.ts +4 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.d.ts.map +1 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.d.ts +4 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.d.ts.map +1 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.js +5 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.js.map +1 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.js +15 -0
- package/build/ReactNativeAppClipModule/ReactNativeAppClipModule.js.map +1 -0
- package/build/ReactNativeAppClipModule/index.d.ts +3 -0
- package/build/ReactNativeAppClipModule/index.d.ts.map +1 -0
- package/build/ReactNativeAppClipModule/index.js +3 -0
- package/build/ReactNativeAppClipModule/index.js.map +1 -0
- package/build/ReactNativeAppClipModule/types.d.ts +9 -0
- package/build/ReactNativeAppClipModule/types.d.ts.map +1 -0
- package/build/ReactNativeAppClipModule/types.js +2 -0
- package/build/ReactNativeAppClipModule/types.js.map +1 -0
- package/build/getBundleIdentifier/getBundleIdentifier.d.ts +4 -0
- package/build/getBundleIdentifier/getBundleIdentifier.d.ts.map +1 -0
- package/build/getBundleIdentifier/getBundleIdentifier.ios.d.ts +4 -0
- package/build/getBundleIdentifier/getBundleIdentifier.ios.d.ts.map +1 -0
- package/build/getBundleIdentifier/getBundleIdentifier.ios.js +11 -0
- package/build/getBundleIdentifier/getBundleIdentifier.ios.js.map +1 -0
- package/build/getBundleIdentifier/getBundleIdentifier.js +5 -0
- package/build/getBundleIdentifier/getBundleIdentifier.js.map +1 -0
- package/build/getBundleIdentifier/index.d.ts +3 -0
- package/build/getBundleIdentifier/index.d.ts.map +1 -0
- package/build/getBundleIdentifier/index.js +3 -0
- package/build/getBundleIdentifier/index.js.map +1 -0
- package/build/getBundleIdentifier/types.d.ts +2 -0
- package/build/getBundleIdentifier/types.d.ts.map +1 -0
- package/build/getBundleIdentifier/types.js +2 -0
- package/build/getBundleIdentifier/types.js.map +1 -0
- package/build/index.d.ts +15 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +23 -0
- package/build/index.js.map +1 -0
- package/build/isClip/index.d.ts +3 -0
- package/build/isClip/index.d.ts.map +1 -0
- package/build/isClip/index.js +3 -0
- package/build/isClip/index.js.map +1 -0
- package/build/isClip/isClip.clip.d.ts +9 -0
- package/build/isClip/isClip.clip.d.ts.map +1 -0
- package/build/isClip/isClip.clip.js +10 -0
- package/build/isClip/isClip.clip.js.map +1 -0
- package/build/isClip/isClip.d.ts +4 -0
- package/build/isClip/isClip.d.ts.map +1 -0
- package/build/isClip/isClip.ios.d.ts +4 -0
- package/build/isClip/isClip.ios.d.ts.map +1 -0
- package/build/isClip/isClip.ios.js +9 -0
- package/build/isClip/isClip.ios.js.map +1 -0
- package/build/isClip/isClip.js +5 -0
- package/build/isClip/isClip.js.map +1 -0
- package/build/isClip/types.d.ts +2 -0
- package/build/isClip/types.d.ts.map +1 -0
- package/build/isClip/types.js +2 -0
- package/build/isClip/types.js.map +1 -0
- package/expo-module.config.json +6 -0
- package/ios/ReactNativeAppClip.podspec +27 -0
- package/ios/ReactNativeAppClipModule.swift +82 -0
- package/ios/reactnativeappclip.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/reactnativeappclip.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/package.json +53 -0
- package/plugin/build/cliPlugin.d.ts +3 -0
- package/plugin/build/cliPlugin.js +26 -0
- package/plugin/build/index.d.ts +17 -0
- package/plugin/build/index.js +63 -0
- package/plugin/build/lib/getAppClipEntitlements.d.ts +8 -0
- package/plugin/build/lib/getAppClipEntitlements.js +39 -0
- package/plugin/build/withCompression.d.ts +5 -0
- package/plugin/build/withCompression.js +100 -0
- package/plugin/build/withConfig.d.ts +8 -0
- package/plugin/build/withConfig.js +66 -0
- package/plugin/build/withEntitlements.d.ts +8 -0
- package/plugin/build/withEntitlements.js +30 -0
- package/plugin/build/withPlist.d.ts +7 -0
- package/plugin/build/withPlist.js +73 -0
- package/plugin/build/withPodfile.d.ts +5 -0
- package/plugin/build/withPodfile.js +82 -0
- package/plugin/build/withXcode.d.ts +8 -0
- package/plugin/build/withXcode.js +51 -0
- package/plugin/build/xcode/addBuildPhases.d.ts +12 -0
- package/plugin/build/xcode/addBuildPhases.js +44 -0
- package/plugin/build/xcode/addPbxGroup.d.ts +6 -0
- package/plugin/build/xcode/addPbxGroup.js +69 -0
- package/plugin/build/xcode/addProductFile.d.ts +5 -0
- package/plugin/build/xcode/addProductFile.js +21 -0
- package/plugin/build/xcode/addTargetDependency.d.ts +4 -0
- package/plugin/build/xcode/addTargetDependency.js +14 -0
- package/plugin/build/xcode/addToPbxNativeTargetSection.d.ts +24 -0
- package/plugin/build/xcode/addToPbxNativeTargetSection.js +21 -0
- package/plugin/build/xcode/addToPbxProjectSection.d.ts +4 -0
- package/plugin/build/xcode/addToPbxProjectSection.js +14 -0
- package/plugin/build/xcode/addXCConfigurationList.d.ts +8 -0
- package/plugin/build/xcode/addXCConfigurationList.js +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# react-native-app-clip
|
|
2
|
+
|
|
3
|
+
> **Warning**
|
|
4
|
+
> Starting with version 0.6.0, react-native-app-clip requires **Expo SDK 53** and **React Native 0.79**. Downgrade to 0.5.1 if you wish to use **Expo SDK 52** and **React Native 0.76**.
|
|
5
|
+
|
|
6
|
+
Expo Config Plugin that generates an App Clip for iOS apps built with Expo.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Install it in your project:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npx expo install react-native-app-clip
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
In your app’s Expo config (app.json, or app.config.js), make sure that react-native-app-clip has been added to the list of plugins. You may optionally provide a name option, which will determine the display name of your App Clip in iOS. If you do not provide a value here, it will be your app’s name appended with " Clip".
|
|
17
|
+
|
|
18
|
+
```app.json
|
|
19
|
+
"expo": {
|
|
20
|
+
"name": "my-app",
|
|
21
|
+
"plugins": [
|
|
22
|
+
["react-native-app-clip", { "name": "My App Clip" }]
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
You can add more parameters to the plugin configuration as specified in the [Additional parameters](#additional-parameters) section below.
|
|
28
|
+
|
|
29
|
+
Generate the native code:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npx expo prebuild
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run the App Clip scheme (Release mode tends to be more reliable):
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npx expo run:ios --configuration Release --scheme
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
After installing the App Clip scheme, you can launch the App Clip:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
xcrun simctl launch <DEVICE-UUID> <APP_CLIP_BUNDLE_ID>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
NOTE: You can find the simulator device UUID by running `xcrun simctl list`. The App Clip Bundle Identifier is the `bundleIdentifier` followed by the `bundleIdSuffix` (see [Additional parameters - bundleIdSuffix](additional-parameters) for more details) joined by a `.`.
|
|
48
|
+
|
|
49
|
+
## Additional parameters:
|
|
50
|
+
|
|
51
|
+
- **name** (string): The public name of the App Clip (displayed when opening it).
|
|
52
|
+
- **enabled** (boolean, default: true): Whether the App Clip should be built.
|
|
53
|
+
- **bundleIdSuffix** (string, default: "Clip"): The suffix that is appended to the bundle id to form the App Clip's bundle id. Please note: If you change this, you need to pass the new suffix when using the isClip() function (e.g. `isClip("AppClip")`).
|
|
54
|
+
- **targetSuffix** (string, default: "Clip"): The suffix that is appended to the target name.
|
|
55
|
+
- **groupIdentifier** (string): Configures an app group to share data between App Clip and full app (see [Apple Developer Docs](https://developer.apple.com/documentation/xcode/configuring-app-groups))
|
|
56
|
+
- **deploymentTarget** (string): Sets the deployment target for the App Clip. If you set this to "16.0", your App Clip can be 15 MB instead of 10 MB.
|
|
57
|
+
- **requestEphemeralUserNotification** (boolean): Enables notifications for the App Clip (see [Apple Developer Docs](https://developer.apple.com/documentation/app_clips/enabling_notifications_in_app_clips))
|
|
58
|
+
- **requestLocationConfirmation** (boolean): Allow App Clip access to location data (see [Apple Developer Docs](https://developer.apple.com/documentation/app_clips/confirming_the_user_s_physical_location))
|
|
59
|
+
- **appleSignin** (boolean): Enable "Sign in with Apple" for the App Clip
|
|
60
|
+
- **applePayMerchantIds** (string[]): Enable Apple Pay capability with provided merchant IDs.
|
|
61
|
+
- **excludedPackages** (string[]): Packages to exclude from autolinking for the App Clip to reduce bundle size (see below).
|
|
62
|
+
- **pushNotifications** (boolean): Enable push notification compatibility for the App Clip
|
|
63
|
+
|
|
64
|
+
## Native capabilities
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import {
|
|
68
|
+
isClip,
|
|
69
|
+
displayOverlay,
|
|
70
|
+
} from "react-native-app-clip";
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**isClip()** allows determining whether the code is currently run within the App Clip and can be used to apply different content and behaviors for the full app and the App Clip.
|
|
74
|
+
|
|
75
|
+
**displayOverlay()** shows the native iOS banner to promote the full app within the App Clip (see [Apple Developer Docs](https://developer.apple.com/documentation/app_clips/recommending_your_app_to_app_clip_users)).
|
|
76
|
+
|
|
77
|
+
## Sharing data between App Clip and full app
|
|
78
|
+
|
|
79
|
+
Data can be shared from the App Clip to the full app by using [`expo-secure-store`](https://docs.expo.dev/versions/latest/sdk/securestore/) from iOS 15.4 onwards. Data is securely shared using the keychain and can be accessed by the full app after installation (see [Apple Developer Docs](https://developer.apple.com/documentation/appclip/sharing-data-between-your-app-clip-and-your-full-app#Review-keychain-usage)).
|
|
80
|
+
|
|
81
|
+
## Before building for release (TestFlight and App Store)
|
|
82
|
+
|
|
83
|
+
Please note that you must register a new App ID for the App Clip in your Apple Developer profile. Under "Certificates, Identifiers & Profiles", go to “Identifiers”, click on the plus icon and select "App IDs" to create a new App ID. Select "App Clip" as the type and on the next screen, select your main app as the "Parent App ID" and enter Clip as the product name (it is crucial that the product name is "Clip" and nothing else. At the bottom of the page, Apple shows a preview of the App Clip Bundle ID. If your main app’s bundle ID is com.example.my-app, the App Clip Bundle ID should now be com.example.my-app.Clip.
|
|
84
|
+
|
|
85
|
+
## How to test the App Clip
|
|
86
|
+
|
|
87
|
+
App Clips can not be tested with Expo Go or expo-dev-client. The best two ways to test the App Clip seem to be the following:
|
|
88
|
+
|
|
89
|
+
### Run in Simulator
|
|
90
|
+
|
|
91
|
+
Build the development client first by running `expo run:ios` and opening the app in Simulator. After doing this once, you can run `expo run:ios --scheme` and select the App Clip scheme ("...Clip") to open the App Clip. You could also add an extra script to your project’s package.json:
|
|
92
|
+
|
|
93
|
+
```package.json
|
|
94
|
+
"scripts": {
|
|
95
|
+
"clip": "expo run:ios --scheme my-appClip"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Now you can simply type "npm run clip" in your terminal to open the App Clip.
|
|
100
|
+
|
|
101
|
+
### Build App Clip with Xcode and open on a connected device
|
|
102
|
+
|
|
103
|
+
Run `expo prebuild -p ios` (see https://docs.expo.dev/workflow/expo-cli/#expo-prebuild) in your Expo project folder to generate the ios folder with all native sources. Then open the file `ios/my-app.xcworkspace` (with my-app being your app’s name) in Xcode. In your project, you should find two targets, one named like your app (e.g. "my-app") and one with a "Clip" suffix (e.g. "my-appClip"). For both targets, select a team in the "Signing & Capabilities" tab and make sure a signing certificate is selected by Xcode. Then, using the menu bar, select "Product", followed by "Scheme", where you should see two themes listed at the bottom of the menu, named after the two targets. Select the scheme that ends with "Clip". Now you can build and run the App Clip (using the menu bar via "Product" followed by "Run" or using the shortcut ⌘R).
|
|
104
|
+
|
|
105
|
+
Launching from Xcode can often fix issues in which the App Clip doesn't show up as an installed app on the device. Once you launch from Xcode once, your App Clip should be available with subsequent CLI builds.
|
|
106
|
+
|
|
107
|
+
### Build for production using EAS Build and test via TestFlight
|
|
108
|
+
|
|
109
|
+
You can build your app and submit it to the App Store (see https://docs.expo.dev/build/introduction/) to test the App Clip using TestFlight. Refer to Apple’s developer docs about testing App Clips: https://developer.apple.com/documentation/app_clips/testing_the_launch_experience_of_your_app_clip.
|
|
110
|
+
|
|
111
|
+
## App Clip file extension (.clip)
|
|
112
|
+
|
|
113
|
+
You can configure an App Clip specific file extension similar to [React Native's native platform extensions](https://reactnative.dev/docs/platform-specific-code#native-specific-extensions-ie-sharing-code-with-nodejs-and-web). Enabling this can help optimize build sizes since only the `.clip` file will be included in the App Clip JS bundle. You can replace heavy assets, large components, or unsupported library features using this file extension. The `.clip` extension preference can be configured in `metro.config.js` by prepending `clip` to each of the existing source extensions when the env variable `BUILDING_FOR_APP_CLIP` is enabled.
|
|
114
|
+
|
|
115
|
+
The App Clip file extension is an advanced optimization feature which requires a slightly more complex build setup. Using this feature is only recommended if you're trying to significantly customize and optimize the JS bundle of your production App Clip. Behavior customization is fully within the control of `metro.config.js`. The below snippet prioritizes `.clip` files, including assets, but you may need to customize further depending on your needs.
|
|
116
|
+
|
|
117
|
+
`BUILDING_FOR_APP_CLIP` is automatically populated within the build stages only for the App Clip build stage. This means that you can continue to create only one iOS build, and the `BUILDING_FOR_APP_CLIP` value will only be set within the context of the App Clip and not within the main app.
|
|
118
|
+
|
|
119
|
+
### Usage
|
|
120
|
+
`metro.config.js`
|
|
121
|
+
```typescript
|
|
122
|
+
if (process.env.BUILDING_FOR_APP_CLIP) {
|
|
123
|
+
console.info("Building for App Clip");
|
|
124
|
+
config.resolver = {
|
|
125
|
+
...config.resolver,
|
|
126
|
+
sourceExts: [].concat(
|
|
127
|
+
config.resolver.sourceExts.map((e) => `clip.${e}`),
|
|
128
|
+
config.resolver.sourceExts,
|
|
129
|
+
),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
```
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./plugin/build");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactNativeAppClipModule.d.ts","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/ReactNativeAppClipModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;AAEvD,QAAA,MAAM,wBAAwB,EAAE,4BAY/B,CAAC;AACF,eAAe,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactNativeAppClipModule.ios.d.ts","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,SAAS,CAAC;;AAIvD,wBAEE"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { requireNativeModule } from "expo-modules-core";
|
|
2
|
+
// It loads the native module object from the JSI or falls back to
|
|
3
|
+
// the bridge module (from NativeModulesProxy) if the remote debugger is on.
|
|
4
|
+
export default requireNativeModule("ReactNativeAppClip");
|
|
5
|
+
//# sourceMappingURL=ReactNativeAppClipModule.ios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactNativeAppClipModule.ios.js","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/ReactNativeAppClipModule.ios.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGxD,kEAAkE;AAClE,4EAA4E;AAC5E,eAAe,mBAAmB,CACjC,oBAAoB,CACpB,CAAC","sourcesContent":["import { requireNativeModule } from \"expo-modules-core\";\nimport { ReactNativeAppClipModuleType } from \"./types\";\n\n// It loads the native module object from the JSI or falls back to\n// the bridge module (from NativeModulesProxy) if the remote debugger is on.\nexport default requireNativeModule<ReactNativeAppClipModuleType>(\n\t\"ReactNativeAppClip\",\n);\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const ReactNativeAppClipModule = {
|
|
2
|
+
getContainerURL: (groupIdentifier) => {
|
|
3
|
+
return null;
|
|
4
|
+
},
|
|
5
|
+
getBundleIdentifier: () => {
|
|
6
|
+
return null;
|
|
7
|
+
},
|
|
8
|
+
displayOverlay: () => { },
|
|
9
|
+
setSharedCredential: () => { },
|
|
10
|
+
getSharedCredential: () => {
|
|
11
|
+
return null;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
export default ReactNativeAppClipModule;
|
|
15
|
+
//# sourceMappingURL=ReactNativeAppClipModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReactNativeAppClipModule.js","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/ReactNativeAppClipModule.ts"],"names":[],"mappings":"AAEA,MAAM,wBAAwB,GAAiC;IAC9D,eAAe,EAAE,CAAC,eAAuB,EAAE,EAAE;QAC5C,OAAO,IAAI,CAAC;IACb,CAAC;IACD,mBAAmB,EAAE,GAAG,EAAE;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,cAAc,EAAE,GAAG,EAAE,GAAE,CAAC;IACxB,mBAAmB,EAAE,GAAG,EAAE,GAAE,CAAC;IAC7B,mBAAmB,EAAE,GAAG,EAAE;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;CACD,CAAC;AACF,eAAe,wBAAwB,CAAC","sourcesContent":["import { ReactNativeAppClipModuleType } from \"./types\";\n\nconst ReactNativeAppClipModule: ReactNativeAppClipModuleType = {\n\tgetContainerURL: (groupIdentifier: string) => {\n\t\treturn null;\n\t},\n\tgetBundleIdentifier: () => {\n\t\treturn null;\n\t},\n\tdisplayOverlay: () => {},\n\tsetSharedCredential: () => {},\n\tgetSharedCredential: () => {\n\t\treturn null;\n\t},\n};\nexport default ReactNativeAppClipModule;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/index.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,MAAM,4BAA4B,CAAC;AAClE,eAAe,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/index.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,MAAM,4BAA4B,CAAC;AAClE,eAAe,wBAAwB,CAAC","sourcesContent":["import ReactNativeAppClipModule from \"./ReactNativeAppClipModule\";\nexport default ReactNativeAppClipModule;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GetBundleIdentiferFn } from "../getBundleIdentifier/types";
|
|
2
|
+
export interface ReactNativeAppClipModuleType {
|
|
3
|
+
getContainerURL: (groupIdentifier: string) => string | null;
|
|
4
|
+
getBundleIdentifier: GetBundleIdentiferFn;
|
|
5
|
+
displayOverlay: () => void;
|
|
6
|
+
setSharedCredential: (groupIdentifier: string, credential: string) => void;
|
|
7
|
+
getSharedCredential: (groupIdentifier: string) => string | null;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AAEpE,MAAM,WAAW,4BAA4B;IAC5C,eAAe,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IAC5D,mBAAmB,EAAE,oBAAoB,CAAC;IAC1C,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,mBAAmB,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,mBAAmB,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAChE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ReactNativeAppClipModule/types.ts"],"names":[],"mappings":"","sourcesContent":["import { GetBundleIdentiferFn } from \"../getBundleIdentifier/types\";\n\nexport interface ReactNativeAppClipModuleType {\n\tgetContainerURL: (groupIdentifier: string) => string | null;\n\tgetBundleIdentifier: GetBundleIdentiferFn;\n\tdisplayOverlay: () => void;\n\tsetSharedCredential: (groupIdentifier: string, credential: string) => void;\n\tgetSharedCredential: (groupIdentifier: string) => string | null;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBundleIdentifier.d.ts","sourceRoot":"","sources":["../../src/getBundleIdentifier/getBundleIdentifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE/C,QAAA,MAAM,mBAAmB,EAAE,oBAE1B,CAAC;AACF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBundleIdentifier.ios.d.ts","sourceRoot":"","sources":["../../src/getBundleIdentifier/getBundleIdentifier.ios.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAG/C,QAAA,MAAM,mBAAmB,EAAE,oBAK1B,CAAC;AACF,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ReactNativeAppClipModule from "../ReactNativeAppClipModule";
|
|
2
|
+
let bundleIdentifier = null;
|
|
3
|
+
const getBundleIdentifier = () => {
|
|
4
|
+
// Bundle identifier doesn't change during runtime
|
|
5
|
+
if (bundleIdentifier)
|
|
6
|
+
return bundleIdentifier;
|
|
7
|
+
bundleIdentifier = ReactNativeAppClipModule.getBundleIdentifier();
|
|
8
|
+
return bundleIdentifier;
|
|
9
|
+
};
|
|
10
|
+
export default getBundleIdentifier;
|
|
11
|
+
//# sourceMappingURL=getBundleIdentifier.ios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBundleIdentifier.ios.js","sourceRoot":"","sources":["../../src/getBundleIdentifier/getBundleIdentifier.ios.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,MAAM,6BAA6B,CAAC;AAGnE,IAAI,gBAAgB,GAAkB,IAAI,CAAC;AAC3C,MAAM,mBAAmB,GAAyB,GAAG,EAAE;IACtD,kDAAkD;IAClD,IAAI,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC9C,gBAAgB,GAAG,wBAAwB,CAAC,mBAAmB,EAAE,CAAC;IAClE,OAAO,gBAAgB,CAAC;AACzB,CAAC,CAAC;AACF,eAAe,mBAAmB,CAAC","sourcesContent":["import ReactNativeAppClipModule from \"../ReactNativeAppClipModule\";\nimport { GetBundleIdentiferFn } from \"./types\";\n\nlet bundleIdentifier: string | null = null;\nconst getBundleIdentifier: GetBundleIdentiferFn = () => {\n\t// Bundle identifier doesn't change during runtime\n\tif (bundleIdentifier) return bundleIdentifier;\n\tbundleIdentifier = ReactNativeAppClipModule.getBundleIdentifier();\n\treturn bundleIdentifier;\n};\nexport default getBundleIdentifier;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getBundleIdentifier.js","sourceRoot":"","sources":["../../src/getBundleIdentifier/getBundleIdentifier.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAyB,GAAG,EAAE;IACtD,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AACF,eAAe,mBAAmB,CAAC","sourcesContent":["import { GetBundleIdentiferFn } from \"./types\";\n\nconst getBundleIdentifier: GetBundleIdentiferFn = () => {\n\treturn null;\n};\nexport default getBundleIdentifier;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/getBundleIdentifier/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/getBundleIdentifier/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,eAAe,mBAAmB,CAAC","sourcesContent":["import getBundleIdentifier from \"./getBundleIdentifier\";\nexport default getBundleIdentifier;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/getBundleIdentifier/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/getBundleIdentifier/types.ts"],"names":[],"mappings":"","sourcesContent":["export type GetBundleIdentiferFn = () => string | null;\n"]}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNativeAppClipModuleType } from "./ReactNativeAppClipModule/types";
|
|
2
|
+
import getBundleIdentifier from "./getBundleIdentifier";
|
|
3
|
+
import isClip from "./isClip";
|
|
4
|
+
export declare const getContainerURL: ReactNativeAppClipModuleType["getContainerURL"];
|
|
5
|
+
export declare const displayOverlay: ReactNativeAppClipModuleType["displayOverlay"];
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use [`setItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoresetitemkey-value-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.
|
|
8
|
+
*/
|
|
9
|
+
export declare const setSharedCredential: ReactNativeAppClipModuleType["setSharedCredential"];
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use [`getItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoregetitemkey-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.
|
|
12
|
+
*/
|
|
13
|
+
export declare const getSharedCredential: ReactNativeAppClipModuleType["getSharedCredential"];
|
|
14
|
+
export { getBundleIdentifier, isClip };
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,eAAO,MAAM,eAAe,EAAE,4BAA4B,CAAC,iBAAiB,CAI3E,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,4BAA4B,CAAC,gBAAgB,CAEzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,4BAA4B,CAAC,qBAAqB,CAKnF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,4BAA4B,CAAC,qBAAqB,CAInF,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC"}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import ReactNativeAppClipModule from "./ReactNativeAppClipModule";
|
|
2
|
+
import getBundleIdentifier from "./getBundleIdentifier";
|
|
3
|
+
import isClip from "./isClip";
|
|
4
|
+
export const getContainerURL = (groupIdentifier) => {
|
|
5
|
+
return ReactNativeAppClipModule.getContainerURL(groupIdentifier);
|
|
6
|
+
};
|
|
7
|
+
export const displayOverlay = () => {
|
|
8
|
+
return ReactNativeAppClipModule.displayOverlay();
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use [`setItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoresetitemkey-value-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.
|
|
12
|
+
*/
|
|
13
|
+
export const setSharedCredential = (groupIdentifier, credential) => {
|
|
14
|
+
return ReactNativeAppClipModule.setSharedCredential(groupIdentifier, credential);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated Use [`getItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoregetitemkey-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.
|
|
18
|
+
*/
|
|
19
|
+
export const getSharedCredential = (groupIdentifier) => {
|
|
20
|
+
return ReactNativeAppClipModule.getSharedCredential(groupIdentifier);
|
|
21
|
+
};
|
|
22
|
+
export { getBundleIdentifier, isClip };
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,wBAAwB,MAAM,4BAA4B,CAAC;AAElE,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,MAAM,MAAM,UAAU,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAAoD,CAC/E,eAAe,EACd,EAAE;IACH,OAAO,wBAAwB,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAmD,GAAG,EAAE;IAClF,OAAO,wBAAwB,CAAC,cAAc,EAAE,CAAC;AAClD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAwD,CACvF,eAAe,EACf,UAAU,EACT,EAAE;IACH,OAAO,wBAAwB,CAAC,mBAAmB,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;AAClF,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAwD,CACvF,eAAe,EACd,EAAE;IACH,OAAO,wBAAwB,CAAC,mBAAmB,CAAC,eAAe,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,CAAC","sourcesContent":["import ReactNativeAppClipModule from \"./ReactNativeAppClipModule\";\nimport { ReactNativeAppClipModuleType } from \"./ReactNativeAppClipModule/types\";\nimport getBundleIdentifier from \"./getBundleIdentifier\";\nimport isClip from \"./isClip\";\n\nexport const getContainerURL: ReactNativeAppClipModuleType[\"getContainerURL\"] = (\n\tgroupIdentifier,\n) => {\n\treturn ReactNativeAppClipModule.getContainerURL(groupIdentifier);\n};\n\nexport const displayOverlay: ReactNativeAppClipModuleType[\"displayOverlay\"] = () => {\n\treturn ReactNativeAppClipModule.displayOverlay();\n};\n\n/**\n * @deprecated Use [`setItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoresetitemkey-value-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.\n */\nexport const setSharedCredential: ReactNativeAppClipModuleType[\"setSharedCredential\"] = (\n\tgroupIdentifier,\n\tcredential,\n) => {\n\treturn ReactNativeAppClipModule.setSharedCredential(groupIdentifier, credential);\n};\n\n/**\n * @deprecated Use [`getItem`](https://docs.expo.dev/versions/latest/sdk/securestore/#securestoregetitemkey-options) from `expo-secure-store` instead. From iOS 15.4 and onwards, App Clip keychain data is shared with the containing app.\n */\nexport const getSharedCredential: ReactNativeAppClipModuleType[\"getSharedCredential\"] = (\n\tgroupIdentifier,\n) => {\n\treturn ReactNativeAppClipModule.getSharedCredential(groupIdentifier);\n};\n\nexport { getBundleIdentifier, isClip };\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/isClip/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/isClip/index.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,UAAU,CAAC;AAC9B,eAAe,MAAM,CAAC","sourcesContent":["import isClip from \"./isClip\";\nexport default isClip;\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IsClipFn } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* If this file is bundled in, that means that the `.clip` extension is configured and the current build target is an app clip.
|
|
4
|
+
*
|
|
5
|
+
* This is more reliable than using the bundle identifier.
|
|
6
|
+
*/
|
|
7
|
+
declare const isClip: IsClipFn;
|
|
8
|
+
export default isClip;
|
|
9
|
+
//# sourceMappingURL=isClip.clip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.clip.d.ts","sourceRoot":"","sources":["../../src/isClip/isClip.clip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC;;;;GAIG;AACH,QAAA,MAAM,MAAM,EAAE,QAEb,CAAC;AACF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* If this file is bundled in, that means that the `.clip` extension is configured and the current build target is an app clip.
|
|
3
|
+
*
|
|
4
|
+
* This is more reliable than using the bundle identifier.
|
|
5
|
+
*/
|
|
6
|
+
const isClip = () => {
|
|
7
|
+
return true;
|
|
8
|
+
};
|
|
9
|
+
export default isClip;
|
|
10
|
+
//# sourceMappingURL=isClip.clip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.clip.js","sourceRoot":"","sources":["../../src/isClip/isClip.clip.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,MAAM,GAAa,GAAG,EAAE;IAC7B,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AACF,eAAe,MAAM,CAAC","sourcesContent":["import { IsClipFn } from \"./types\";\n\n/**\n * If this file is bundled in, that means that the `.clip` extension is configured and the current build target is an app clip.\n *\n * This is more reliable than using the bundle identifier.\n */\nconst isClip: IsClipFn = () => {\n\treturn true;\n};\nexport default isClip;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.d.ts","sourceRoot":"","sources":["../../src/isClip/isClip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,QAAA,MAAM,MAAM,EAAE,QAEb,CAAC;AACF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.ios.d.ts","sourceRoot":"","sources":["../../src/isClip/isClip.ios.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,QAAA,MAAM,MAAM,EAAE,QAMb,CAAC;AACF,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import getBundleIdentifier from "../getBundleIdentifier";
|
|
2
|
+
const isClip = (bundleIdSuffix = "Clip") => {
|
|
3
|
+
const bundleIdentifier = getBundleIdentifier();
|
|
4
|
+
const isClip = bundleIdentifier?.slice(bundleIdentifier.lastIndexOf(".") + 1) ===
|
|
5
|
+
bundleIdSuffix;
|
|
6
|
+
return isClip;
|
|
7
|
+
};
|
|
8
|
+
export default isClip;
|
|
9
|
+
//# sourceMappingURL=isClip.ios.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.ios.js","sourceRoot":"","sources":["../../src/isClip/isClip.ios.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,wBAAwB,CAAC;AAGzD,MAAM,MAAM,GAAa,CAAC,cAAc,GAAG,MAAM,EAAE,EAAE;IACpD,MAAM,gBAAgB,GAAG,mBAAmB,EAAE,CAAC;IAC/C,MAAM,MAAM,GACX,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9D,cAAc,CAAC;IAChB,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AACF,eAAe,MAAM,CAAC","sourcesContent":["import getBundleIdentifier from \"../getBundleIdentifier\";\nimport { IsClipFn } from \"./types\";\n\nconst isClip: IsClipFn = (bundleIdSuffix = \"Clip\") => {\n\tconst bundleIdentifier = getBundleIdentifier();\n\tconst isClip =\n\t\tbundleIdentifier?.slice(bundleIdentifier.lastIndexOf(\".\") + 1) ===\n\t\tbundleIdSuffix;\n\treturn isClip;\n};\nexport default isClip;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isClip.js","sourceRoot":"","sources":["../../src/isClip/isClip.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAa,GAAG,EAAE;IAC7B,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AACF,eAAe,MAAM,CAAC","sourcesContent":["import { IsClipFn } from \"./types\";\n\nconst isClip: IsClipFn = () => {\n\treturn false;\n};\nexport default isClip;\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/isClip/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,CAAC,cAAc,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/isClip/types.ts"],"names":[],"mappings":"","sourcesContent":["export type IsClipFn = (bundleIdSuffix?: string) => boolean;\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'ReactNativeAppClip'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.description = package['description']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.homepage = package['homepage']
|
|
13
|
+
s.platforms = { :ios => '13.4', :tvos => '13.4' }
|
|
14
|
+
s.swift_version = '5.4'
|
|
15
|
+
s.source = { git: 'https://github.com/bndkt/react-native-app-clip' }
|
|
16
|
+
s.static_framework = true
|
|
17
|
+
|
|
18
|
+
s.dependency 'ExpoModulesCore'
|
|
19
|
+
|
|
20
|
+
# Swift/Objective-C compatibility
|
|
21
|
+
s.pod_target_xcconfig = {
|
|
22
|
+
'DEFINES_MODULE' => 'YES',
|
|
23
|
+
'SWIFT_COMPILATION_MODE' => 'wholemodule'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
s.source_files = "**/*.{h,m,swift}"
|
|
27
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import ExpoModulesCore
|
|
2
|
+
import StoreKit
|
|
3
|
+
|
|
4
|
+
internal class MissingCurrentWindowSceneException: Exception {
|
|
5
|
+
override var reason: String {
|
|
6
|
+
"Cannot determine the current window scene in which to present the modal for requesting a review."
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
internal class MissingContainerURLException: Exception {
|
|
11
|
+
override var reason: String {
|
|
12
|
+
"Cannot determine the container URL."
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public class ReactNativeAppClipModule: Module {
|
|
17
|
+
// Each module class must implement the definition function. The definition consists of components
|
|
18
|
+
// that describes the module's functionality and behavior.
|
|
19
|
+
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
20
|
+
public func definition() -> ModuleDefinition {
|
|
21
|
+
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
22
|
+
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
23
|
+
// The module will be accessible from `requireNativeModule('ReactNativeAppClip')` in JavaScript.
|
|
24
|
+
Name("ReactNativeAppClip")
|
|
25
|
+
|
|
26
|
+
// Get containerURL to share data between App Clip and app
|
|
27
|
+
// https://developer.apple.com/documentation/app_clips/sharing_data_between_your_app_clip_and_your_full_app
|
|
28
|
+
Function("getContainerURL") { (groupIdentifier: String) -> String in
|
|
29
|
+
// let logger = Logger()
|
|
30
|
+
// logger.info("getContainerURL() called with groupIdentifier \(groupIdentifier)")
|
|
31
|
+
|
|
32
|
+
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)
|
|
33
|
+
|
|
34
|
+
if let unwrapped = containerURL {
|
|
35
|
+
// logger.info("containerURL is \(unwrapped)")
|
|
36
|
+
return unwrapped.absoluteString
|
|
37
|
+
} else {
|
|
38
|
+
// logger.info("containerURL is nil")
|
|
39
|
+
return ""
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Function("setSharedCredential") { (groupIdentifier: String, credential: String) -> Void in
|
|
44
|
+
// let logger = Logger()
|
|
45
|
+
// logger.info("setSharedCredential() called with groupIdentifier \(groupIdentifier) and credential \(credential)")
|
|
46
|
+
|
|
47
|
+
let groupUserDefaults = UserDefaults(suiteName: groupIdentifier)
|
|
48
|
+
groupUserDefaults?.set(credential, forKey: "SavedUserID")
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Function("getSharedCredential") { (groupIdentifier: String) -> String? in
|
|
52
|
+
// let logger = Logger()
|
|
53
|
+
// logger.info("getSharedCredential() called with groupIdentifier \(groupIdentifier)")
|
|
54
|
+
|
|
55
|
+
let groupUserDefaults = UserDefaults(suiteName: groupIdentifier)
|
|
56
|
+
let credential = groupUserDefaults?.string(forKey: "SavedUserID")
|
|
57
|
+
|
|
58
|
+
// logger.info("credential is \(credential)")
|
|
59
|
+
|
|
60
|
+
return credential
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Display overlay to advertise full app
|
|
64
|
+
// https://developer.apple.com/documentation/app_clips/recommending_your_app_to_app_clip_users
|
|
65
|
+
AsyncFunction("displayOverlay") {
|
|
66
|
+
if #available(iOS 16, *) {
|
|
67
|
+
guard let currentScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
|
|
68
|
+
throw MissingCurrentWindowSceneException()
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let config = SKOverlay.AppClipConfiguration(position: .bottom)
|
|
72
|
+
let overlay = SKOverlay(configuration: config)
|
|
73
|
+
overlay.present(in: currentScene)
|
|
74
|
+
}
|
|
75
|
+
}.runOnQueue(DispatchQueue.main)
|
|
76
|
+
|
|
77
|
+
Function("getBundleIdentifier") { () -> String? in
|
|
78
|
+
let bundleIdentifier = Bundle.main.bundleIdentifier
|
|
79
|
+
return bundleIdentifier
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|