expo-share-intent
Version:
use native share intent for ios and android with expo
148 lines (147 loc) • 8.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.withShareExtensionXcodeTarget = void 0;
const config_plugins_1 = require("@expo/config-plugins");
const constants_1 = require("./constants");
const writeIosShareExtensionFiles_1 = require("./writeIosShareExtensionFiles");
//───────────────────────────────────────────────────────────────────────────
// Helper: pull DEVELOPMENT_TEAM from the main-app target's build settings
//───────────────────────────────────────────────────────────────────────────
function getMainAppDevelopmentTeam(pbx) {
const configs = pbx.pbxXCBuildConfigurationSection();
for (const key in configs) {
const config = configs[key];
const bs = config.buildSettings;
if (!bs || !bs.PRODUCT_NAME)
continue;
const productName = bs.PRODUCT_NAME?.replace(/"/g, "");
// Ignore other extensions/widgets
if (productName &&
(productName.includes("Extension") || productName.includes("Widget"))) {
continue;
}
const developmentTeam = bs.DEVELOPMENT_TEAM?.replace(/"/g, "");
if (developmentTeam) {
console.log(`[expo-share-intent] Found DEVELOPMENT_TEAM='${developmentTeam}' from main app configuration.`);
return developmentTeam;
}
}
console.warn("[expo-share-intent] No DEVELOPMENT_TEAM found in main app build settings. Developer will need to manually add Dev Team.");
return null;
}
const withShareExtensionXcodeTarget = (config, parameters) => {
return (0, config_plugins_1.withXcodeProject)(config, async (config) => {
const extensionName = (0, constants_1.getShareExtensionName)(parameters);
const platformProjectRoot = config.modRequest.platformProjectRoot;
const scheme = config.scheme;
const appIdentifier = config.ios?.bundleIdentifier;
const shareExtensionIdentifier = (0, constants_1.getShareExtensionBundledIdentifier)(appIdentifier, parameters);
const currentProjectVersion = config.ios.buildNumber || "1";
const marketingVersion = config.version;
// Write extension files first
await (0, writeIosShareExtensionFiles_1.writeShareExtensionFiles)(platformProjectRoot, scheme, appIdentifier, parameters, config.name);
const pbxProject = config.modResults;
/* ------------------------------------------------------------------ */
/* 1. Bail out early if target/group already exist */
/* ------------------------------------------------------------------ */
const existingTarget = pbxProject.pbxTargetByName(extensionName);
if (existingTarget) {
console.log(`[expo-share-intent] ${extensionName} already exists in project. Skipping…`);
return config;
}
const existingGroups = pbxProject.hash.project.objects.PBXGroup;
const groupExists = Object.values(existingGroups).some((group) => group && group.name === extensionName);
if (groupExists) {
console.log(`[expo-share-intent] ${extensionName} group already exists in project. Skipping…`);
return config;
}
/* ------------------------------------------------------------------ */
/* 2. Resolve DEVELOPMENT_TEAM */
/* ------------------------------------------------------------------ */
const detectedDevTeam = getMainAppDevelopmentTeam(pbxProject);
const devTeam = detectedDevTeam ?? undefined;
/* ------------------------------------------------------------------ */
/* 3. Define all files for the extension */
/* ------------------------------------------------------------------ */
const sourceFiles = [constants_1.shareExtensionViewControllerFileName];
const resourceFiles = [
constants_1.shareExtensionStoryBoardFileName,
constants_1.shareExtensionPreprocessorFileName,
"PrivacyInfo.xcprivacy",
];
const configFiles = [
constants_1.shareExtensionInfoFileName,
constants_1.shareExtensionEntitlementsFileName,
];
const allFiles = [...sourceFiles, ...resourceFiles, ...configFiles];
/* ------------------------------------------------------------------ */
/* 4. Create target, group & build phases (CORRECTED APPROACH) */
/* ------------------------------------------------------------------ */
// 4.1 Create PBXGroup for the extension using addPbxGroup (OneSignal style)
const extGroup = pbxProject.addPbxGroup(allFiles, extensionName, extensionName);
// 4.2 Add the new PBXGroup to the top level group
const groups = pbxProject.hash.project.objects.PBXGroup;
Object.keys(groups).forEach(function (key) {
if (typeof groups[key] === "object" &&
groups[key].name === undefined &&
groups[key].path === undefined) {
pbxProject.addToPbxGroup(extGroup.uuid, key);
}
});
// 4.3 WORK AROUND for addTarget BUG (from OneSignal)
// Xcode projects don't contain these if there is only one target
const projObjects = pbxProject.hash.project.objects;
projObjects.PBXTargetDependency = projObjects.PBXTargetDependency || {};
projObjects.PBXContainerItemProxy = projObjects.PBXContainerItemProxy || {};
// 4.4 Create native target
const target = pbxProject.addTarget(extensionName, "app_extension", extensionName);
// 4.5 Add build phases to the new target
pbxProject.addBuildPhase(sourceFiles, // Add source files directly to the build phase
"PBXSourcesBuildPhase", "Sources", target.uuid);
pbxProject.addBuildPhase(resourceFiles, // Add resource files directly to the build phase
"PBXResourcesBuildPhase", "Resources", target.uuid);
pbxProject.addBuildPhase([], "PBXFrameworksBuildPhase", "Frameworks", target.uuid);
/* ------------------------------------------------------------------ */
/* 5. Build-settings configuration */
/* ------------------------------------------------------------------ */
const configurations = pbxProject.pbxXCBuildConfigurationSection();
for (const key in configurations) {
const config = configurations[key];
const buildSettingsObj = config.buildSettings;
if (!buildSettingsObj)
continue;
if (typeof buildSettingsObj["PRODUCT_NAME"] !== "undefined" &&
buildSettingsObj["PRODUCT_NAME"] === `"${extensionName}"`) {
buildSettingsObj["CLANG_ENABLE_MODULES"] = "YES";
buildSettingsObj["INFOPLIST_FILE"] =
`"${extensionName}/${constants_1.shareExtensionInfoFileName}"`;
buildSettingsObj["CODE_SIGN_ENTITLEMENTS"] =
`"${extensionName}/${constants_1.shareExtensionEntitlementsFileName}"`;
buildSettingsObj["CODE_SIGN_STYLE"] = "Automatic";
buildSettingsObj["CURRENT_PROJECT_VERSION"] =
`"${currentProjectVersion}"`;
buildSettingsObj["GENERATE_INFOPLIST_FILE"] = "YES";
buildSettingsObj["MARKETING_VERSION"] = `"${marketingVersion}"`;
buildSettingsObj["PRODUCT_BUNDLE_IDENTIFIER"] =
`"${shareExtensionIdentifier}"`;
buildSettingsObj["SWIFT_EMIT_LOC_STRINGS"] = "YES";
buildSettingsObj["SWIFT_VERSION"] = "5.0";
buildSettingsObj["TARGETED_DEVICE_FAMILY"] = `"1,2"`;
if (devTeam) {
buildSettingsObj["DEVELOPMENT_TEAM"] = devTeam;
}
}
}
/* ------------------------------------------------------------------ */
/* 6. Apply DevelopmentTeam to both targets */
/* ------------------------------------------------------------------ */
if (devTeam) {
pbxProject.addTargetAttribute("DevelopmentTeam", devTeam);
const shareTarget = pbxProject.pbxTargetByName(extensionName);
pbxProject.addTargetAttribute("DevelopmentTeam", devTeam, shareTarget);
}
console.log(`[expo-share-intent] Successfully created ${extensionName} target with files`);
return config;
});
};
exports.withShareExtensionXcodeTarget = withShareExtensionXcodeTarget;