diff --git a/package.json b/package.json index 9a3ef16..c3c347f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-app-clip", - "version": "0.9.1", + "version": "0.9.2", "description": "Config plugin to add an App Clip to a React Native iOS app", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/plugin/src/lib/getAppClipIcon.ts b/plugin/src/lib/getAppClipIcon.ts new file mode 100644 index 0000000..24c9e00 --- /dev/null +++ b/plugin/src/lib/getAppClipIcon.ts @@ -0,0 +1,18 @@ +import type { ConfigPlugin } from "expo/config-plugins"; +import path from "node:path"; + +export function getAppClipIcon( + config: Pick[0], "icon" | "ios">, +): { name: string; fileName: string } | undefined { + let icon = config.ios?.icon || config.icon; + if (icon && typeof icon === "object" && !icon.light && !icon.dark && !icon.tinted) { + icon = config.icon; + } + if (typeof icon !== "string" || path.extname(icon) !== ".icon") { + return undefined; + } + return { + name: path.basename(icon, ".icon"), + fileName: path.basename(icon), + }; +} diff --git a/plugin/src/withPlist.ts b/plugin/src/withPlist.ts index 8cde400..206d21c 100644 --- a/plugin/src/withPlist.ts +++ b/plugin/src/withPlist.ts @@ -7,6 +7,8 @@ import { import fs from "node:fs"; import path from "node:path"; +import { getAppClipIcon } from "./lib/getAppClipIcon"; + /** * 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. */ @@ -74,6 +76,10 @@ export const withPlist: ConfigPlugin<{ } infoPlist.CFBundleName = "$(PRODUCT_MODULE_NAME)"; + const appClipIcon = getAppClipIcon(config); + if (appClipIcon) { + infoPlist.CFBundleIconName = appClipIcon.name; + } fs.mkdirSync(path.dirname(filePath), { recursive: true, diff --git a/plugin/src/withXcode.ts b/plugin/src/withXcode.ts index 3bce829..7ef984f 100644 --- a/plugin/src/withXcode.ts +++ b/plugin/src/withXcode.ts @@ -1,7 +1,12 @@ -import { type ConfigPlugin, withXcodeProject } from "expo/config-plugins"; +import { + IOSConfig, + type ConfigPlugin, + withXcodeProject, +} from "expo/config-plugins"; import fs from "node:fs"; import path from "node:path"; +import { getAppClipIcon } from "./lib/getAppClipIcon"; import { addBuildPhases } from "./xcode/addBuildPhases"; import { addPbxGroup } from "./xcode/addPbxGroup"; import { modifyAppDelegate } from "./xcode/modifyAppDelegate"; @@ -20,6 +25,7 @@ export const withXcode: ConfigPlugin<{ }> = (config, { name, targetName, bundleIdentifier, deploymentTarget, enableCompression }) => { return withXcodeProject(config, (config) => { const xcodeProject = config.modResults; + const appClipIcon = getAppClipIcon(config); const targetUuid = xcodeProject.generateUuid(); const groupName = "Embed App Clips"; @@ -32,6 +38,7 @@ export const withXcode: ConfigPlugin<{ bundleIdentifier, deploymentTarget, appleTeamId: config.ios?.appleTeamId, + appIconName: appClipIcon?.name, }); const productFile = addProductFile(xcodeProject, { @@ -54,6 +61,7 @@ export const withXcode: ConfigPlugin<{ projectName: projectName as string, targetName, platformProjectRoot, + appIconFileName: appClipIcon?.fileName, }); if (enableCompression) { @@ -74,8 +82,19 @@ export const withXcode: ConfigPlugin<{ groupName, productFile, enableCompression, + resourcesPhaseName: appClipIcon ? "Resources" : undefined, }); + if (appClipIcon) { + IOSConfig.XcodeUtils.addResourceFileToGroup({ + filepath: appClipIcon.fileName, + groupName: targetName, + project: xcodeProject, + isBuildFile: true, + targetUuid, + }); + } + return config; }); }; diff --git a/plugin/src/xcode/addBuildPhases.ts b/plugin/src/xcode/addBuildPhases.ts index a513715..e9038b7 100644 --- a/plugin/src/xcode/addBuildPhases.ts +++ b/plugin/src/xcode/addBuildPhases.ts @@ -8,6 +8,7 @@ export function addBuildPhases( groupName, productFile, enableCompression, + resourcesPhaseName, }: { targetUuid: string; groupName: string; @@ -18,6 +19,7 @@ export function addBuildPhases( group: string; }; enableCompression?: boolean; + resourcesPhaseName?: string; }, ) { const buildPath = `"$(CONTENTS_FOLDER_PATH)/AppClips"`; @@ -81,7 +83,7 @@ export function addBuildPhases( xcodeProject.addBuildPhase( ["Images.xcassets", "SplashScreen.storyboard", "Supporting/Expo.plist"], "PBXResourcesBuildPhase", - groupName, + resourcesPhaseName ?? groupName, targetUuid, folderType, buildPath, diff --git a/plugin/src/xcode/addPbxGroup.ts b/plugin/src/xcode/addPbxGroup.ts index 33d7644..b83ee2d 100644 --- a/plugin/src/xcode/addPbxGroup.ts +++ b/plugin/src/xcode/addPbxGroup.ts @@ -8,7 +8,13 @@ export function addPbxGroup( projectName, targetName, platformProjectRoot, - }: { projectName: string; targetName: string; platformProjectRoot: string }, + appIconFileName, + }: { + projectName: string; + targetName: string; + platformProjectRoot: string; + appIconFileName?: string; + }, ) { const targetPath = path.join(platformProjectRoot, targetName); @@ -34,6 +40,14 @@ export function addPbxGroup( ); copyFolderRecursiveSync(imagesXcassetsSource, targetPath); + if (appIconFileName) { + fs.cpSync( + path.join(platformProjectRoot, projectName, appIconFileName), + path.join(targetPath, appIconFileName), + { recursive: true }, + ); + } + // Add PBX group const { uuid: pbxGroupUuid } = xcodeProject.addPbxGroup( [ diff --git a/plugin/src/xcode/addXCConfigurationList.ts b/plugin/src/xcode/addXCConfigurationList.ts index 34b1242..563d026 100644 --- a/plugin/src/xcode/addXCConfigurationList.ts +++ b/plugin/src/xcode/addXCConfigurationList.ts @@ -9,6 +9,7 @@ export function addXCConfigurationList( bundleIdentifier, deploymentTarget, appleTeamId, + appIconName, }: { name: string; targetName: string; @@ -16,10 +17,13 @@ export function addXCConfigurationList( bundleIdentifier: string; deploymentTarget: string; appleTeamId?: string; + appIconName?: string; }, ) { const commonBuildSettings: Record = { - ASSETCATALOG_COMPILER_APPICON_NAME: "AppIcon", + ASSETCATALOG_COMPILER_APPICON_NAME: appIconName + ? JSON.stringify(appIconName) + : "AppIcon", CLANG_ENABLE_MODULES: "YES", CURRENT_PROJECT_VERSION: `"${currentProjectVersion}"`, INFOPLIST_FILE: `${targetName}/Info.plist`,