@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/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@trentrand/react-native-app-clip",
|
|
3
|
+
"version": "0.6.2-beta.0",
|
|
4
|
+
"description": "Config plugin to add an App Clip to a React Native iOS app",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"types": "build/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"ios",
|
|
9
|
+
"plugin/build",
|
|
10
|
+
"build",
|
|
11
|
+
"README.md",
|
|
12
|
+
"expo-module.config.json",
|
|
13
|
+
"app.plugin.js"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "expo-module build",
|
|
17
|
+
"build:plugin": "expo-module build plugin",
|
|
18
|
+
"clean": "expo-module clean",
|
|
19
|
+
"lint": "expo-module lint",
|
|
20
|
+
"test": "expo-module test",
|
|
21
|
+
"prepare": "expo-module prepare",
|
|
22
|
+
"prepublishOnly": "expo-module prepublishOnly",
|
|
23
|
+
"expo-module": "expo-module",
|
|
24
|
+
"open:ios": "xed example/ios",
|
|
25
|
+
"open:android": "open -a \"Android Studio\" example/android"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"react-native",
|
|
29
|
+
"expo",
|
|
30
|
+
"react-native-app-clip",
|
|
31
|
+
"ReactNativeAppClip"
|
|
32
|
+
],
|
|
33
|
+
"repository": "https://github.com/bndkt/react-native-app-clip",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/bndkt/react-native-app-clip/issues"
|
|
36
|
+
},
|
|
37
|
+
"author": "Benedikt Müller <91166910+bndkt@users.noreply.github.com> (https://github.com/bndkt)",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"homepage": "https://github.com/bndkt/react-native-app-clip#readme",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@expo/config-plugins": "~10.0.0",
|
|
42
|
+
"@expo/plist": "~0.3.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"expo-module-scripts": "^4.0.0",
|
|
46
|
+
"expo-modules-core": "~2.3.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"expo": "*",
|
|
50
|
+
"react": "*",
|
|
51
|
+
"react-native": "*"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = void 0;
|
|
4
|
+
const run = async (config, exclude) => {
|
|
5
|
+
// Validation
|
|
6
|
+
if (typeof config !== "object") {
|
|
7
|
+
throw new Error("config must be an object");
|
|
8
|
+
}
|
|
9
|
+
if (!config.dependencies) {
|
|
10
|
+
throw new Error("config must have a dependencies key");
|
|
11
|
+
}
|
|
12
|
+
if (!Array.isArray(exclude)) {
|
|
13
|
+
throw new Error("exclude must be an array");
|
|
14
|
+
}
|
|
15
|
+
for (const packageName of exclude) {
|
|
16
|
+
if (typeof packageName !== "string") {
|
|
17
|
+
throw new Error("exclude must be an array of strings");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
// Removing excluded packages
|
|
21
|
+
for (const packageName of exclude) {
|
|
22
|
+
delete config.dependencies[packageName];
|
|
23
|
+
}
|
|
24
|
+
console.log(JSON.stringify(config));
|
|
25
|
+
};
|
|
26
|
+
exports.run = run;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ConfigPlugin } from "expo/config-plugins";
|
|
2
|
+
declare const withAppClip: ConfigPlugin<{
|
|
3
|
+
name?: string;
|
|
4
|
+
enabled?: boolean;
|
|
5
|
+
bundleIdSuffix?: string;
|
|
6
|
+
targetSuffix?: string;
|
|
7
|
+
groupIdentifier?: string;
|
|
8
|
+
deploymentTarget?: string;
|
|
9
|
+
requestEphemeralUserNotification?: boolean;
|
|
10
|
+
requestLocationConfirmation?: boolean;
|
|
11
|
+
appleSignin?: boolean;
|
|
12
|
+
applePayMerchantIds?: string[];
|
|
13
|
+
excludedPackages?: string[];
|
|
14
|
+
pushNotifications?: boolean;
|
|
15
|
+
enableCompression?: boolean;
|
|
16
|
+
}>;
|
|
17
|
+
export default withAppClip;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
4
|
+
const withConfig_1 = require("./withConfig");
|
|
5
|
+
const withCompression_1 = require("./withCompression");
|
|
6
|
+
const withEntitlements_1 = require("./withEntitlements");
|
|
7
|
+
const withPlist_1 = require("./withPlist");
|
|
8
|
+
const withPodfile_1 = require("./withPodfile");
|
|
9
|
+
const withXcode_1 = require("./withXcode");
|
|
10
|
+
const DeviceFamily_1 = require("@expo/config-plugins/build/ios/DeviceFamily");
|
|
11
|
+
const withAppClip = (config, { name, enabled, bundleIdSuffix, targetSuffix, groupIdentifier, deploymentTarget, requestEphemeralUserNotification, requestLocationConfirmation, appleSignin, applePayMerchantIds, excludedPackages, pushNotifications, enableCompression, } = {}) => {
|
|
12
|
+
name ??= "Clip";
|
|
13
|
+
bundleIdSuffix ??= "Clip";
|
|
14
|
+
targetSuffix ??= "Clip";
|
|
15
|
+
deploymentTarget ??= "15.1";
|
|
16
|
+
requestEphemeralUserNotification ??= false;
|
|
17
|
+
requestLocationConfirmation ??= false;
|
|
18
|
+
appleSignin ??= false;
|
|
19
|
+
enabled ??= true;
|
|
20
|
+
pushNotifications ??= false;
|
|
21
|
+
if (!enabled) {
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
if (!config.ios?.bundleIdentifier) {
|
|
25
|
+
throw new Error("No bundle identifier specified in app config");
|
|
26
|
+
}
|
|
27
|
+
const bundleIdentifier = `${config.ios.bundleIdentifier}.${bundleIdSuffix}`;
|
|
28
|
+
const targetName = `${config_plugins_1.IOSConfig.XcodeUtils.sanitizedName(config.name)}${targetSuffix}`;
|
|
29
|
+
const modifiedConfig = (0, config_plugins_1.withPlugins)(config, [
|
|
30
|
+
DeviceFamily_1.withDeviceFamily,
|
|
31
|
+
[
|
|
32
|
+
withConfig_1.withConfig,
|
|
33
|
+
{ targetName, bundleIdentifier, appleSignin, applePayMerchantIds, pushNotifications },
|
|
34
|
+
],
|
|
35
|
+
[
|
|
36
|
+
withEntitlements_1.withEntitlements,
|
|
37
|
+
{ targetName, groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications },
|
|
38
|
+
],
|
|
39
|
+
[withPodfile_1.withPodfile, { targetName, excludedPackages }],
|
|
40
|
+
[
|
|
41
|
+
withPlist_1.withPlist,
|
|
42
|
+
{
|
|
43
|
+
targetName,
|
|
44
|
+
deploymentTarget,
|
|
45
|
+
requestEphemeralUserNotification,
|
|
46
|
+
requestLocationConfirmation,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
[
|
|
50
|
+
withXcode_1.withXcode,
|
|
51
|
+
{
|
|
52
|
+
name,
|
|
53
|
+
targetName,
|
|
54
|
+
bundleIdentifier,
|
|
55
|
+
deploymentTarget,
|
|
56
|
+
enableCompression,
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
[withCompression_1.withCompression, { targetName, enableCompression }],
|
|
60
|
+
]);
|
|
61
|
+
return modifiedConfig;
|
|
62
|
+
};
|
|
63
|
+
exports.default = withAppClip;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ExportedConfigWithProps, InfoPlist } from "expo/config-plugins";
|
|
2
|
+
export declare function getAppClipEntitlements(iosConfig: ExportedConfigWithProps["ios"], { groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications, }: {
|
|
3
|
+
groupIdentifier?: string;
|
|
4
|
+
appleSignin: boolean;
|
|
5
|
+
applePayMerchantIds?: string[];
|
|
6
|
+
pushNotifications: boolean;
|
|
7
|
+
}): InfoPlist;
|
|
8
|
+
export declare function addApplicationGroupsEntitlement(entitlements: InfoPlist, groupIdentifier?: string): InfoPlist;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAppClipEntitlements = getAppClipEntitlements;
|
|
4
|
+
exports.addApplicationGroupsEntitlement = addApplicationGroupsEntitlement;
|
|
5
|
+
function getAppClipEntitlements(iosConfig, { groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications, }) {
|
|
6
|
+
const appBundleIdentifier = iosConfig?.bundleIdentifier;
|
|
7
|
+
const entitlements = {
|
|
8
|
+
"com.apple.developer.parent-application-identifiers": [
|
|
9
|
+
`$(AppIdentifierPrefix)${appBundleIdentifier}`,
|
|
10
|
+
],
|
|
11
|
+
"com.apple.developer.on-demand-install-capable": true,
|
|
12
|
+
};
|
|
13
|
+
addApplicationGroupsEntitlement(entitlements, groupIdentifier);
|
|
14
|
+
if (appleSignin) {
|
|
15
|
+
entitlements["com.apple.developer.applesignin"] = ["Default"];
|
|
16
|
+
}
|
|
17
|
+
if (applePayMerchantIds) {
|
|
18
|
+
entitlements["com.apple.developer.in-app-payments"] = applePayMerchantIds;
|
|
19
|
+
}
|
|
20
|
+
if (pushNotifications) {
|
|
21
|
+
// XCode automatically changes this to "production" when archiving https://stackoverflow.com/a/42293632/4047926
|
|
22
|
+
entitlements["aps-environment"] = "development";
|
|
23
|
+
}
|
|
24
|
+
if (iosConfig?.associatedDomains) {
|
|
25
|
+
entitlements["com.apple.developer.associated-domains"] =
|
|
26
|
+
iosConfig.associatedDomains;
|
|
27
|
+
}
|
|
28
|
+
return entitlements;
|
|
29
|
+
}
|
|
30
|
+
function addApplicationGroupsEntitlement(entitlements, groupIdentifier) {
|
|
31
|
+
if (groupIdentifier) {
|
|
32
|
+
const existingApplicationGroups = entitlements["com.apple.security.application-groups"] ?? [];
|
|
33
|
+
entitlements["com.apple.security.application-groups"] = [
|
|
34
|
+
groupIdentifier,
|
|
35
|
+
...existingApplicationGroups,
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
return entitlements;
|
|
39
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withCompression = void 0;
|
|
7
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const withCompression = (config, { targetName, enableCompression = false }) => {
|
|
11
|
+
if (!enableCompression) {
|
|
12
|
+
return config;
|
|
13
|
+
}
|
|
14
|
+
// Use withDangerousMod but ensure it runs AFTER all other mods
|
|
15
|
+
// by adding it at priority 0 (runs last)
|
|
16
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
17
|
+
"ios",
|
|
18
|
+
async (config) => {
|
|
19
|
+
const projectRoot = config.modRequest.platformProjectRoot;
|
|
20
|
+
console.log("🔧 Configuring App Clip compression...");
|
|
21
|
+
// Modify AppDelegate to handle decompression
|
|
22
|
+
const appDelegatePath = path_1.default.join(projectRoot, targetName, "AppDelegate.swift");
|
|
23
|
+
if (fs_1.default.existsSync(appDelegatePath)) {
|
|
24
|
+
modifyAppDelegate(appDelegatePath);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.warn(`⚠️ AppDelegate not found at ${appDelegatePath}`);
|
|
28
|
+
}
|
|
29
|
+
return config;
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
};
|
|
33
|
+
exports.withCompression = withCompression;
|
|
34
|
+
function modifyAppDelegate(appDelegatePath) {
|
|
35
|
+
let content = fs_1.default.readFileSync(appDelegatePath, "utf8");
|
|
36
|
+
// Check if already modified
|
|
37
|
+
if (content.includes("decompressZlibBundle")) {
|
|
38
|
+
console.log("✅ AppDelegate already configured for compression");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// Add Compression import
|
|
42
|
+
if (!content.includes("import Compression")) {
|
|
43
|
+
content = content.replace(/(import.*\n)+/, (imports) => imports + "import Compression\n");
|
|
44
|
+
}
|
|
45
|
+
// Find and replace the bundleURL() function
|
|
46
|
+
const bundleURLPattern = /override func bundleURL\(\) -> URL\? \{[\s\S]*?#if DEBUG[\s\S]*?#else[\s\S]*?#endif[\s\S]*?\}/;
|
|
47
|
+
if (bundleURLPattern.test(content)) {
|
|
48
|
+
content = content.replace(bundleURLPattern, `override func bundleURL() -> URL? {
|
|
49
|
+
#if DEBUG
|
|
50
|
+
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: ".expo/.virtual-metro-entry")
|
|
51
|
+
#else
|
|
52
|
+
return decompressedBundleURL()
|
|
53
|
+
#endif
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// MARK: - Bundle Decompression
|
|
57
|
+
|
|
58
|
+
private func decompressedBundleURL() -> URL? {
|
|
59
|
+
// Try compressed bundle first
|
|
60
|
+
if let zlibPath = Bundle.main.url(forResource: "main.jsbundle", withExtension: "zlib") {
|
|
61
|
+
return decompressZlibBundle(at: zlibPath)
|
|
62
|
+
}
|
|
63
|
+
// Fallback to uncompressed
|
|
64
|
+
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private func decompressZlibBundle(at compressedURL: URL) -> URL? {
|
|
68
|
+
let decompressedPath = NSTemporaryDirectory() + "main.jsbundle"
|
|
69
|
+
let decompressedURL = URL(fileURLWithPath: decompressedPath)
|
|
70
|
+
|
|
71
|
+
// ALWAYS remove existing temp file to ensure we don't load stale code after an update
|
|
72
|
+
try? FileManager.default.removeItem(at: decompressedURL)
|
|
73
|
+
|
|
74
|
+
do {
|
|
75
|
+
let compressedData = try Data(contentsOf: compressedURL)
|
|
76
|
+
|
|
77
|
+
// Decompress using NSData decompression (available iOS 13+)
|
|
78
|
+
guard let decompressedData = try? (compressedData as NSData).decompressed(using: .zlib) as Data else {
|
|
79
|
+
print("❌ Failed to decompress bundle")
|
|
80
|
+
return nil
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Use atomic write to ensure integrity
|
|
84
|
+
try decompressedData.write(to: decompressedURL, options: .atomic)
|
|
85
|
+
|
|
86
|
+
print("✅ Bundle decompressed: \\(compressedData.count / 1024) KB → \\(decompressedData.count / 1024) KB")
|
|
87
|
+
|
|
88
|
+
return decompressedURL
|
|
89
|
+
} catch {
|
|
90
|
+
print("❌ Decompression error: \\(error)")
|
|
91
|
+
return nil
|
|
92
|
+
}
|
|
93
|
+
}`);
|
|
94
|
+
fs_1.default.writeFileSync(appDelegatePath, content);
|
|
95
|
+
console.log("✅ Modified AppDelegate for decompression");
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.warn("⚠️ Could not find bundleURL() function in AppDelegate");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withConfig = void 0;
|
|
4
|
+
const getAppClipEntitlements_1 = require("./lib/getAppClipEntitlements");
|
|
5
|
+
const withConfig = (config, { targetName, bundleIdentifier, appleSignin, applePayMerchantIds, pushNotifications }) => {
|
|
6
|
+
let configIndex = null;
|
|
7
|
+
config.extra?.eas?.build?.experimental?.ios?.appExtensions?.forEach((ext, index) => {
|
|
8
|
+
if (ext.targetName === targetName) {
|
|
9
|
+
configIndex = index;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
if (!configIndex) {
|
|
13
|
+
config.extra = {
|
|
14
|
+
...config.extra,
|
|
15
|
+
eas: {
|
|
16
|
+
...config.extra?.eas,
|
|
17
|
+
build: {
|
|
18
|
+
...config.extra?.eas?.build,
|
|
19
|
+
experimental: {
|
|
20
|
+
...config.extra?.eas?.build?.experimental,
|
|
21
|
+
ios: {
|
|
22
|
+
...config.extra?.eas?.build?.experimental?.ios,
|
|
23
|
+
appExtensions: [
|
|
24
|
+
...(config.extra?.eas?.build?.experimental?.ios
|
|
25
|
+
?.appExtensions ?? []),
|
|
26
|
+
{
|
|
27
|
+
targetName,
|
|
28
|
+
bundleIdentifier,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
configIndex = 0;
|
|
37
|
+
}
|
|
38
|
+
if (configIndex !== null && config.extra) {
|
|
39
|
+
const appClipConfig = config.extra.eas.build.experimental.ios.appExtensions[configIndex];
|
|
40
|
+
appClipConfig.entitlements = {
|
|
41
|
+
...appClipConfig.entitlements,
|
|
42
|
+
...(0, getAppClipEntitlements_1.getAppClipEntitlements)(config.ios, {
|
|
43
|
+
appleSignin,
|
|
44
|
+
applePayMerchantIds,
|
|
45
|
+
// groupIdentifier, // Throws an error in EAS
|
|
46
|
+
pushNotifications,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Entitlements
|
|
51
|
+
config.ios = {
|
|
52
|
+
...config.ios,
|
|
53
|
+
entitlements: {
|
|
54
|
+
// ...addApplicationGroupsEntitlement(
|
|
55
|
+
// config.ios?.entitlements ?? {},
|
|
56
|
+
// groupIdentifier,
|
|
57
|
+
// ),
|
|
58
|
+
...config.ios?.entitlements,
|
|
59
|
+
"com.apple.developer.associated-appclip-app-identifiers": [
|
|
60
|
+
`$(AppIdentifierPrefix)${bundleIdentifier}`,
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
return config;
|
|
65
|
+
};
|
|
66
|
+
exports.withConfig = withConfig;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withEntitlements = void 0;
|
|
7
|
+
const plist_1 = __importDefault(require("@expo/plist"));
|
|
8
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const getAppClipEntitlements_1 = require("./lib/getAppClipEntitlements");
|
|
12
|
+
const withEntitlements = (config, { targetName, groupIdentifier, appleSignin, applePayMerchantIds, pushNotifications }) => {
|
|
13
|
+
return (0, config_plugins_1.withInfoPlist)(config, (config) => {
|
|
14
|
+
const targetPath = node_path_1.default.join(config.modRequest.platformProjectRoot, targetName);
|
|
15
|
+
const filePath = node_path_1.default.join(targetPath, `${targetName}.entitlements`);
|
|
16
|
+
if (config.ios === undefined) {
|
|
17
|
+
throw new Error("Missing iOS config");
|
|
18
|
+
}
|
|
19
|
+
const appClipEntitlements = (0, getAppClipEntitlements_1.getAppClipEntitlements)(config.ios, {
|
|
20
|
+
groupIdentifier,
|
|
21
|
+
appleSignin,
|
|
22
|
+
applePayMerchantIds,
|
|
23
|
+
pushNotifications,
|
|
24
|
+
});
|
|
25
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), { recursive: true });
|
|
26
|
+
node_fs_1.default.writeFileSync(filePath, plist_1.default.build(appClipEntitlements));
|
|
27
|
+
return config;
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
exports.withEntitlements = withEntitlements;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withPlist = void 0;
|
|
7
|
+
const plist_1 = __importDefault(require("@expo/plist"));
|
|
8
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
/**
|
|
12
|
+
* List of keys that are not allowed in the Info.plist due to not being supported in App Clip. Add to this array as new build issues arise.
|
|
13
|
+
*/
|
|
14
|
+
const DisallowedPlistKeys = [
|
|
15
|
+
"UIBackgroundModes",
|
|
16
|
+
];
|
|
17
|
+
const withPlist = (config, { targetName, deploymentTarget, requestEphemeralUserNotification, requestLocationConfirmation, }) => {
|
|
18
|
+
return (0, config_plugins_1.withInfoPlist)(config, (config) => {
|
|
19
|
+
const targetPath = node_path_1.default.join(config.modRequest.platformProjectRoot, targetName);
|
|
20
|
+
// Info.plist
|
|
21
|
+
const filePath = node_path_1.default.join(targetPath, "Info.plist");
|
|
22
|
+
const infoPlist = {
|
|
23
|
+
NSAppClip: {
|
|
24
|
+
NSAppClipRequestEphemeralUserNotification: requestEphemeralUserNotification,
|
|
25
|
+
NSAppClipRequestLocationConfirmation: requestLocationConfirmation,
|
|
26
|
+
},
|
|
27
|
+
NSAppTransportSecurity: {
|
|
28
|
+
NSAllowsArbitraryLoads: config.developmentClient,
|
|
29
|
+
NSExceptionDomains: {
|
|
30
|
+
localhost: {
|
|
31
|
+
NSExceptionAllowsInsecureHTTPLoads: config.developmentClient,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
NSAllowsLocalNetworking: config.developmentClient,
|
|
35
|
+
},
|
|
36
|
+
CFBundleName: "$(PRODUCT_NAME)",
|
|
37
|
+
CFBundleDisplayName: "$(PRODUCT_NAME)",
|
|
38
|
+
CFBundleIdentifier: "$(PRODUCT_BUNDLE_IDENTIFIER)",
|
|
39
|
+
CFBundleVersion: "$(CURRENT_PROJECT_VERSION)",
|
|
40
|
+
CFBundleExecutable: "$(EXECUTABLE_NAME)",
|
|
41
|
+
CFBundlePackageType: "$(PRODUCT_BUNDLE_PACKAGE_TYPE)",
|
|
42
|
+
CFBundleShortVersionString: config.version,
|
|
43
|
+
UIViewControllerBasedStatusBarAppearance: "NO",
|
|
44
|
+
UILaunchStoryboardName: "SplashScreen",
|
|
45
|
+
UIRequiresFullScreen: true,
|
|
46
|
+
MinimumOSVersion: deploymentTarget,
|
|
47
|
+
};
|
|
48
|
+
if (config.ios?.infoPlist) {
|
|
49
|
+
for (const key of Object.keys(config.ios?.infoPlist)) {
|
|
50
|
+
if (config.ios?.infoPlist && !DisallowedPlistKeys.some((disallowedKey) => disallowedKey === key)) {
|
|
51
|
+
infoPlist[key] = config.ios.infoPlist[key];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(filePath), {
|
|
56
|
+
recursive: true,
|
|
57
|
+
});
|
|
58
|
+
node_fs_1.default.writeFileSync(filePath, plist_1.default.build(infoPlist));
|
|
59
|
+
// Expo.plist
|
|
60
|
+
const expoPlistFilePath = node_path_1.default.join(targetPath, "Supporting/Expo.plist");
|
|
61
|
+
const expoPlist = {
|
|
62
|
+
EXUpdatesRuntimeVersion: "exposdk:51.0.0", // TODO
|
|
63
|
+
// EXUpdatesURL: "", // TODO
|
|
64
|
+
EXUpdatesEnabled: false,
|
|
65
|
+
};
|
|
66
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(expoPlistFilePath), {
|
|
67
|
+
recursive: true,
|
|
68
|
+
});
|
|
69
|
+
node_fs_1.default.writeFileSync(expoPlistFilePath, plist_1.default.build(expoPlist));
|
|
70
|
+
return config;
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
exports.withPlist = withPlist;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.withPodfile = void 0;
|
|
7
|
+
const generateCode_1 = require("@expo/config-plugins/build/utils/generateCode");
|
|
8
|
+
const config_plugins_1 = require("expo/config-plugins");
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const withPodfile = (config, { targetName, excludedPackages }) => {
|
|
12
|
+
// return config;
|
|
13
|
+
return (0, config_plugins_1.withDangerousMod)(config, [
|
|
14
|
+
"ios",
|
|
15
|
+
(config) => {
|
|
16
|
+
const podFilePath = node_path_1.default.join(config.modRequest.platformProjectRoot, "Podfile");
|
|
17
|
+
let podfileContent = node_fs_1.default.readFileSync(podFilePath).toString();
|
|
18
|
+
const useExpoModules = excludedPackages && excludedPackages.length > 0
|
|
19
|
+
? `exclude = ["${excludedPackages.join(`", "`)}"]\n use_expo_modules!(exclude: exclude)`
|
|
20
|
+
: "use_expo_modules!";
|
|
21
|
+
const appClipTarget = `
|
|
22
|
+
target '${targetName}' do
|
|
23
|
+
${useExpoModules}
|
|
24
|
+
|
|
25
|
+
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
|
|
26
|
+
config_command = ['node', '-e', "process.argv=['', '', 'config'];require('@react-native-community/cli').run()"];
|
|
27
|
+
else
|
|
28
|
+
config_command = [
|
|
29
|
+
'npx',
|
|
30
|
+
'expo-modules-autolinking',
|
|
31
|
+
'react-native-config',
|
|
32
|
+
'--json',
|
|
33
|
+
'--platform',
|
|
34
|
+
'ios'
|
|
35
|
+
]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Running the command in the same manner as \`use_react_native\` then running that result through our cliPlugin
|
|
39
|
+
json, message, status = Pod::Executable.capture_command(config_command[0], config_command[1..], capture: :both)
|
|
40
|
+
if not status.success?
|
|
41
|
+
Pod::UI.warn "The command: '#{config_command.join(" ").bold.yellow}' returned a status code of #{status.exitstatus.to_s.bold.red}, #{message}", [
|
|
42
|
+
"App Clip autolinking failed. Please ensure autolinking works correctly for the main app target and try again.",
|
|
43
|
+
]
|
|
44
|
+
exit(status.exitstatus)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# \`react-native-app-clip\` resolves to react-native-app-clip/build/index.js
|
|
48
|
+
clip_command = [
|
|
49
|
+
'node',
|
|
50
|
+
'--no-warnings',
|
|
51
|
+
'--eval',
|
|
52
|
+
'require(require.resolve(\\'react-native-app-clip\\')+\\'/../../plugin/build/cliPlugin.js\\').run(' + json + ', [${(excludedPackages ?? []).map((packageName) => `"${packageName}"`).join(", ")}])'
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
config = use_native_modules!(clip_command)
|
|
56
|
+
|
|
57
|
+
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
|
|
58
|
+
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
|
|
59
|
+
|
|
60
|
+
use_react_native!(
|
|
61
|
+
:path => config[:reactNativePath],
|
|
62
|
+
:hermes_enabled => podfile_properties['expo.jsEngine'] == nil || podfile_properties['expo.jsEngine'] == 'hermes',
|
|
63
|
+
# An absolute path to your application root.
|
|
64
|
+
:app_path => "#{Pod::Config.instance.installation_root}/..",
|
|
65
|
+
:privacy_file_aggregation_enabled => podfile_properties['apple.privacyManifestAggregationEnabled'] != 'false',
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
`;
|
|
69
|
+
podfileContent = (0, generateCode_1.mergeContents)({
|
|
70
|
+
tag: "Generated by react-native-app-clip",
|
|
71
|
+
src: podfileContent,
|
|
72
|
+
newSrc: appClipTarget,
|
|
73
|
+
anchor: "use_expo_modules!",
|
|
74
|
+
offset: 0,
|
|
75
|
+
comment: "#",
|
|
76
|
+
}).contents;
|
|
77
|
+
node_fs_1.default.writeFileSync(podFilePath, podfileContent);
|
|
78
|
+
return config;
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
};
|
|
82
|
+
exports.withPodfile = withPodfile;
|