Skip to content

Commit

Permalink
fix: app plugin spillovers (#37)
Browse files Browse the repository at this point in the history
* chore: clean up plists

* chore: update podfile.lock

* Quick fix for spill over

* Working with build settings, with some spillover

* Clean up

Clean up config plugins

* Add withExpoExperimentalAppExtension

* Revert to publish js bundle

* Remove expo-constants dependency

* Move appleTeamId to new place, remove from config plugin

* v0.2.0

* Apply suggestions from code review

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
robertherber and coderabbitai[bot] authored Jan 26, 2025
1 parent acc212f commit 28cd9a1
Show file tree
Hide file tree
Showing 33 changed files with 474 additions and 315 deletions.
30 changes: 25 additions & 5 deletions app.plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,38 @@ const { createRunOncePlugin } = require("expo/config-plugins");

const withCopyTargetFolder = require("./config-plugin/withCopyTargetFolder");
const withEntitlementsPlugin = require("./config-plugin/withEntitlements");
const withExpoExperimentalAppExtension = require("./config-plugin/withExperimentalExpoAppExtensions");
const withInfoPlistAppGroup = require("./config-plugin/withInfoPlistAppGroup");
const {
withTargetEntitlements,
} = require("./config-plugin/withTargetEntitlements");
const withXcodeSettings = require("./config-plugin/withXCodeSettings");
const pkg = require("./package.json");

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appleTeamId: string; match?: string; appGroup: string; copyToTargetFolder?: boolean }>} */
/** @type {import('@expo/config-plugins').ConfigPlugin<{ appleTeamId?: string; match?: string; appGroup: string; copyToTargetFolder?: boolean }>} */
const withActivityMonitorExtensionPlugin = (config, props) => {
if (!props || !props.appGroup || typeof props.appleTeamId !== "string") {
if (!props || !props.appGroup) {
throw Error(
"'appGroup' and 'appleTeamId' props are required for react-native-device-activity config plugin",
"'appGroup' is required for react-native-device-activity config plugin",
);
}

return withTargetsDir(
withEntitlementsPlugin(withCopyTargetFolder(config, props), props),
return withXcodeSettings(
withTargetEntitlements(
withInfoPlistAppGroup(
withTargetsDir(
withEntitlementsPlugin(
withCopyTargetFolder(
withExpoExperimentalAppExtension(config, props),
props,
),
props,
),
),
props,
),
props,
),
props,
);
};
Expand Down
42 changes: 0 additions & 42 deletions config-plugin/withCopyTargetFolder.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const { default: plist } = require("@expo/plist");
const fs = require("fs");

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appGroup: string; copyToTargetFolder?: boolean }>} */
Expand Down Expand Up @@ -38,47 +37,6 @@ const withCopyTargetFolder = (
}
}

// find all entitlements files in the projectTargetFolderPath
const entitlementsFiles = fs
.readdirSync(projectTargetFolderPath, { recursive: true })
.filter((file) => file.endsWith(".entitlements"));

for (const entitlementsFile of entitlementsFiles) {
const entitlementsFilePath =
projectTargetFolderPath + "/" + entitlementsFile;

const entitlementsFileContents = fs.readFileSync(
entitlementsFilePath,
"utf8",
);

const parsedEntitlements = plist.parse(entitlementsFileContents);

if (parsedEntitlements["com.apple.security.application-groups"]) {
parsedEntitlements["com.apple.security.application-groups"] = [appGroup];
}

const modifiedEntitlementsFileContents = plist.build(parsedEntitlements);

fs.writeFileSync(entitlementsFilePath, modifiedEntitlementsFileContents);
}

const swiftFiles = fs
.readdirSync(projectTargetFolderPath, { recursive: true })
.filter((file) => file.endsWith(".swift"));

for (const swiftFile of swiftFiles) {
const swiftFilePath = projectTargetFolderPath + "/" + swiftFile;
const swiftFileContents = fs.readFileSync(swiftFilePath, "utf8");

const modifiedSwiftFileContents = swiftFileContents.replace(
"group.ActivityMonitor",
appGroup,
);

fs.writeFileSync(swiftFilePath, modifiedSwiftFileContents);
}

return config;
};

Expand Down
6 changes: 4 additions & 2 deletions config-plugin/withEntitlements.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ const withEntitlementsPlugin = (config, { appGroup }) =>
withEntitlementsPlist(config, (config) => {
// todo: make this configurable - but would requiring changes in both Swift code and the /target/Info.plist to make sense
config.modResults["com.apple.security.application-groups"] = [
...(config.modResults["com.apple.security.application-groups"] ?? []),
appGroup ?? "group.ActivityMonitor",
...(config.modResults["com.apple.security.application-groups"]?.filter(
(group) => group !== appGroup,
) ?? []),
appGroup,
];
config.modResults["com.apple.developer.family-controls"] = true;

Expand Down
35 changes: 35 additions & 0 deletions config-plugin/withExperimentalExpoAppExtensions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const { targets } = require("./withTargetEntitlements");

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appGroup: string; }>} */
const withExpoExperimentalAppExtensionFlags = (config, props) => {
config.extra = {
...config.extra,
eas: {
...config.extra?.eas,
build: {
...config.extra?.eas?.build,
experimental: {
...config.extra?.eas?.build?.experimental,
ios: {
...config.extra?.eas?.build?.experimental?.ios,
appExtensions: targets.map((targetName) => {
return {
targetName,
bundleIdentifier:
config.ios.bundleIdentifier + "." + targetName,
entitlements: {
"com.apple.developer.family-controls": true,
"com.apple.security.application-groups": [props.appGroup],
},
};
}),
},
},
},
},
};

return config;
};

module.exports = withExpoExperimentalAppExtensionFlags;
12 changes: 12 additions & 0 deletions config-plugin/withInfoPlistAppGroup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const { withInfoPlist } = require("expo/config-plugins");

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appGroup: string }>} */
const withInfoPlistAppGroup = (config) => {
return withInfoPlist(config, (config) => {
config.modResults.REACT_NATIVE_DEVICE_ACTIVITY_APP_GROUP =
"$(REACT_NATIVE_DEVICE_ACTIVITY_APP_GROUP)";
return config;
});
};

module.exports = withInfoPlistAppGroup;
49 changes: 49 additions & 0 deletions config-plugin/withTargetEntitlements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const { default: plist } = require("@expo/plist");
const fs = require("fs");

const targets = [
"ActivityMonitorExtension",
"ShieldConfiguration",
"ShieldAction",
];

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appGroup: string; }>} */
const withTargetEntitlements = (config, { appGroup }) => {
const projectRoot = config._internal.projectRoot;
const path = require('path');

// eslint-disable-next-line no-undef
const projectTargetFolderPath = path.join(projectRoot, "targets");
// find all entitlements files in the projectTargetFolderPath
const entitlementsFiles = fs
.readdirSync(projectTargetFolderPath, { recursive: true })
.filter(
(file) =>
targets.some((target) => file.startsWith(target)) &&
file.endsWith(".entitlements"),
);

for (const entitlementsFile of entitlementsFiles) {
const entitlementsFilePath =
projectTargetFolderPath + "/" + entitlementsFile;

const entitlementsFileContents = fs.readFileSync(
entitlementsFilePath,
"utf8",
);

const parsedEntitlements = plist.parse(entitlementsFileContents);

if (parsedEntitlements["com.apple.security.application-groups"]) {
parsedEntitlements["com.apple.security.application-groups"] = [appGroup];
}

const modifiedEntitlementsFileContents = plist.build(parsedEntitlements);

fs.writeFileSync(entitlementsFilePath, modifiedEntitlementsFileContents);
}

return config;
};

module.exports = { withTargetEntitlements, targets };
27 changes: 27 additions & 0 deletions config-plugin/withXCodeSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { withXcodeProject } = require("@expo/config-plugins");

/** @type {import('@expo/config-plugins').ConfigPlugin<{ appGroup: string }>} */
const withXcodeSettings = (config, { appGroup }) => {
return withXcodeProject(config, (newConfig) => {
const xcodeProject = newConfig.modResults;

const settings = {
REACT_NATIVE_DEVICE_ACTIVITY_APP_GROUP: appGroup,
};

const configurations = xcodeProject.pbxXCBuildConfigurationSection();

for (const key in configurations) {
// could be trimmed down to main target + react-native-device-activity targets, but since it's the name is so specific this should be fine
if (typeof configurations[key].buildSettings !== "undefined") {
const buildSettingsObj = configurations[key].buildSettings;
for (const key in settings) {
buildSettingsObj[key] = settings[key];
}
}
}
return newConfig;
});
};

module.exports = withXcodeSettings;
2 changes: 1 addition & 1 deletion example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"backgroundColor": "#ffffff"
},
"ios": {
"appleTeamId": "34SE8X7Q58",
"supportsTablet": true,
"bundleIdentifier": "expo.modules.deviceactivity.example"
},
Expand Down Expand Up @@ -48,7 +49,6 @@
[
"../app.plugin.js",
{
"appleTeamId": "34SE8X7Q58",
"appGroup": "group.ActivityMonitor",
"copyToTargetFolder": false
}
Expand Down
14 changes: 14 additions & 0 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,17 @@ target 'reactnativedeviceactivityexample' do

pod 'SwiftLint'
end


# apple-targets-extension-loader -- Dynamic loading of target configurations
Dir.glob(File.join(__dir__, '..', 'targets', '**', 'pods.rb')).each do |target_file|
target_name = File.basename(File.dirname(target_file))
target target_name do
# Create a new binding with access to necessary methods and variables
target_binding = binding
target_binding.local_variable_set(:podfile_properties, podfile_properties)

# Evaluate the target file content in the new binding
eval(File.read(target_file), target_binding, target_file)
end
end
2 changes: 1 addition & 1 deletion example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,6 @@ SPEC CHECKSUMS:
SwiftLint: 92196976e597b9afec5dbe374810103e6c1d9d7c
Yoga: 950bbfd7e6f04790fdb51149ed51df41f329fcc8

PODFILE CHECKSUM: 5ae09240dec8db7b55ecff135c6659568a0c6d16
PODFILE CHECKSUM: b8b40c46183fad3b03c145dfc75dd8fc64203c70

COCOAPODS: 1.16.2
Loading

0 comments on commit 28cd9a1

Please sign in to comment.