@config-plugins/react-native-siri-shortcut
Version:
Config plugin for react-native-siri-shortcut package
181 lines (161 loc) • 5.09 kB
text/typescript
import {
mergeContents,
MergeResults,
} from "@expo/config-plugins/build/utils/generateCode";
import {
type ConfigPlugin,
createRunOncePlugin,
withAppDelegate,
withInfoPlist,
withEntitlementsPlist,
withDangerousMod,
} from "expo/config-plugins";
import fs from "fs";
import { globSync } from "glob";
import path from "path";
/**
* Apply react-native-siri-shortcut configuration for Expo SDK 44 projects.
*/
const withReactNativeSiriShortcut: ConfigPlugin<void | string[]> = (
config,
activityTypes,
) => {
withSiriShortcutAppDelegate(config);
withSiriEntitlements(config);
const items = activityTypes || [];
if (!Array.isArray(items) || !items.length) {
return config;
}
withInfoPlist(config, (config) => {
config.modResults.NSUserActivityTypes = items;
return config;
});
return config;
};
export function addSiriShortcutAppDelegateImport(
src: string,
lang: string,
): MergeResults | null {
if (lang !== "swift") {
// ObjC
return mergeContents({
tag: "react-native-siri-shortcut",
src,
newSrc: "#import <RNSiriShortcuts/RNSiriShortcuts.h>",
anchor: /#import "AppDelegate\.h"/,
offset: 1,
comment: "//",
});
}
return null;
}
export function addSiriShortcutAppDelegateInit(
src: string,
lang: string,
): MergeResults {
if (lang === "swift") {
return mergeContents({
tag: "react-native-siri-shortcut-delegate",
src,
newSrc:
" RNSSSiriShortcuts.application(application, continue: userActivity, restorationHandler: restorationHandler)",
anchor:
/return super.application\(application,(\s+)?continue:(\s+)?userActivity,(\s+)?restorationHandler:(\s+)?restorationHandler\)/,
offset: -1,
comment: "//",
});
}
return mergeContents({
tag: "react-native-siri-shortcut-delegate",
src,
newSrc:
" [RNSSSiriShortcuts application:application continueUserActivity:userActivity restorationHandler:restorationHandler];",
anchor:
/ return \[super application:application continueUserActivity:userActivity restorationHandler:restorationHandler\] \|\| result;/,
offset: -1,
comment: "//",
});
}
export function addSiriShortcutBridgingHeaderImport(src: string): MergeResults {
return mergeContents({
tag: "react-native-siri-shortcut",
src,
newSrc: "#import <RNSiriShortcuts/RNSiriShortcuts.h>",
anchor: /\/\//,
offset: 4,
comment: "//",
});
}
/** Append the siri entitlement on iOS */
const withSiriEntitlements: ConfigPlugin = (config) => {
return withEntitlementsPlist(config, (config) => {
config.modResults["com.apple.developer.siri"] = true;
return config;
});
};
const withSiriShortcutAppDelegate: ConfigPlugin = (config) => {
// Quick dirty hack to support Swift AppDelegate
withDangerousMod(config, [
"ios",
async (config) => {
const [using] = globSync("*-Bridging-Header.h", {
absolute: true,
cwd: path.join(
config.modRequest.platformProjectRoot,
config.modRequest.projectName!,
),
});
if (!using) {
throw new Error(
"Cannot find bridging header. Please make sure you have a bridging header in your project.",
);
}
const src = await fs.promises.readFile(using, "utf-8");
const res = addSiriShortcutBridgingHeaderImport(src);
await fs.promises.writeFile(using, res.contents, "utf-8");
return config;
},
]);
return withAppDelegate(config, (config) => {
if (!["objc", "objcpp", "swift"].includes(config.modResults.language)) {
throw new Error(
"Cannot setup Siri Shortcut because the AppDelegate is not in a support language:" +
` ${config.modResults.language}. Only ObjC, ObjCpp and Swift are supported.`,
);
}
try {
config.modResults.contents =
addSiriShortcutAppDelegateImport(
config.modResults.contents,
config.modResults.language,
)?.contents ?? config.modResults.contents;
config.modResults.contents = addSiriShortcutAppDelegateInit(
config.modResults.contents,
config.modResults.language,
).contents;
} catch (error: any) {
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;
}
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",
};
export default createRunOncePlugin(
withReactNativeSiriShortcut,
pkg.name,
pkg.version,
);