Skip to content

Commit

Permalink
Merge pull request #8 from urbanairship/addDevTeam
Browse files Browse the repository at this point in the history
add devTeam and default service extension
  • Loading branch information
Ulrico972 authored Dec 13, 2024
2 parents f418f16 + 6ea9239 commit 7578cf2
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Airship Expo Plugin Changelog

## Version 1.3.2-beta - December 013, 2024
Beta version that fixes the Notification Service Extension for EAS builds.

## Version 1.3.1 - December 06, 2024
Patch version that fixes the support for Aiship Notification Service Extension when using `use_frameworks`.

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "airship-expo-plugin",
"version": "1.3.1",
"version": "1.3.2-beta",
"description": "Airship Expo config plugin",
"main": "./app.plugin.js",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// NotificationService.swift


import AirshipServiceExtension

class AirshipNotificationService: UANotificationServiceExtension {

}
10 changes: 9 additions & 1 deletion plugin/src/withAirship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@ export type AirshipIOSPluginProps = {
/**
* Optional. The local path to a custom Notification Service Extension.
*/
notificationService?: string;
notificationService?: 'DEFAULT_AIRSHIP_SERVICE_EXTENSION' | string;
/**
* Optional. Airship will use a default one if not provided.
* The local path to a Notification Service Extension Info.plist.
*/
notificationServiceInfo?: string;
/**
* Optional. Defaults to NotificationServiceExtension if not provided.
*/
notificationServiceTargetName?: string;
/**
* Optional. The Apple Development Team ID used to configure the Notification Service Extension target.
*/
developmentTeamID?: string;
}

export type AirshipPluginProps = {
Expand Down
85 changes: 66 additions & 19 deletions plugin/src/withAirshipIOS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import {

import { readFile, writeFileSync, existsSync, mkdirSync } from 'fs';
import { basename, join } from 'path';
import assert from 'assert';

import { ExpoConfig } from '@expo/config-types';

import { AirshipIOSPluginProps } from './withAirship';
import { mergeContents, MergeResults } from '@expo/config-plugins/build/utils/generateCode';

const NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME = "AirshipNotificationServiceExtension";
const DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME = "NotificationServiceExtension";
const NOTIFICATION_SERVICE_FILE_NAME = "AirshipNotificationService.swift";
const NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME = "AirshipNotificationServiceExtension-Info.plist";
const NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME = "NotificationServiceExtension-Info.plist";

const withCapabilities: ConfigPlugin<AirshipIOSPluginProps> = (config, props) => {
return withInfoPlist(config, (plist) => {
Expand Down Expand Up @@ -54,17 +57,18 @@ async function writeNotificationServiceFilesAsync(props: AirshipIOSPluginProps,

const pluginDir = require.resolve("airship-expo-plugin/package.json");
const sourceDir = join(pluginDir, "../plugin/NotificationServiceExtension/");

const extensionPath = join(projectRoot, "ios", NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME);
const targetName = props.notificationServiceTargetName ?? DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME
const extensionPath = join(projectRoot, "ios", targetName);

if (!existsSync(extensionPath)) {
mkdirSync(extensionPath, { recursive: true });
}

// Copy the NotificationService.swift file into the iOS expo project as AirshipNotificationService.swift.
readFile(props.notificationService, 'utf8', (err, data) => {
var notificationServiceFile = props.notificationService == "DEFAULT_AIRSHIP_SERVICE_EXTENSION" ? join(sourceDir, NOTIFICATION_SERVICE_FILE_NAME) : props.notificationService;
readFile(notificationServiceFile, 'utf8', (err, data) => {
if (err || !data) {
console.error("Airship couldn't read file " + props.notificationService);
console.error("Airship couldn't read file " + notificationServiceFile);
console.error(err);
return;
}
Expand All @@ -78,31 +82,34 @@ async function writeNotificationServiceFilesAsync(props: AirshipIOSPluginProps,
writeFileSync(join(extensionPath, NOTIFICATION_SERVICE_FILE_NAME), data);
});

// Copy the Info.plist (default to AirshipNotificationServiceExtension-Info.plist if null) file into the iOS expo project as AirshipNotificationServiceExtension-Info.plist.
// Copy the Info.plist (default to NotificationServiceExtension-Info.plist if null) file into the iOS expo project.
readFile(props.notificationServiceInfo ?? join(sourceDir, NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME), 'utf8', (err, data) => {
if (err || !data) {
console.error("Airship couldn't read file " + (props.notificationServiceInfo ?? join(sourceDir, NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME)));
console.error(err);
return;
}
writeFileSync(join(extensionPath, NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME), data);
const infoPlistFilename = props.notificationServiceTargetName ? props.notificationServiceTargetName + "-Info.plist" : NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME;
writeFileSync(join(extensionPath, infoPlistFilename), data);
});
};

const withExtensionTargetInXcodeProject: ConfigPlugin<AirshipIOSPluginProps> = (config, props) => {
const targetName = props.notificationServiceTargetName ?? DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME

return withXcodeProject(config, newConfig => {
const xcodeProject = newConfig.modResults;

if (!!xcodeProject.pbxTargetByName(NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME)) {
console.log(NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME + " already exists in project. Skipping...");
if (!!xcodeProject.pbxTargetByName(targetName)) {
console.log(targetName + " already exists in project. Skipping...");
return newConfig;
}

const infoPlistFilename = props.notificationServiceTargetName ? props.notificationServiceTargetName + "-Info.plist" : NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME;
// Create new PBXGroup for the extension
const extGroup = xcodeProject.addPbxGroup(
[NOTIFICATION_SERVICE_FILE_NAME, NOTIFICATION_SERVICE_INFO_PLIST_FILE_NAME],
NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME,
NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME
[NOTIFICATION_SERVICE_FILE_NAME, infoPlistFilename],
targetName,
targetName
);

// Add the new PBXGroup to the top level group. This makes the
Expand All @@ -125,10 +132,10 @@ const withExtensionTargetInXcodeProject: ConfigPlugin<AirshipIOSPluginProps> = (
// Add the Notification Service Extension Target
// This adds PBXTargetDependency and PBXContainerItemProxy
const notificationServiceExtensionTarget = xcodeProject.addTarget(
NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME,
targetName,
"app_extension",
NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME,
`${config.ios?.bundleIdentifier}.${NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME}`
targetName,
`${config.ios?.bundleIdentifier}.${targetName}`
);

// Add build phases to the new Target
Expand All @@ -155,22 +162,29 @@ const withExtensionTargetInXcodeProject: ConfigPlugin<AirshipIOSPluginProps> = (
const configurations = xcodeProject.pbxXCBuildConfigurationSection();
for (const key in configurations) {
if (typeof configurations[key].buildSettings !== "undefined"
&& configurations[key].buildSettings.PRODUCT_NAME == `"${NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME}"`
&& configurations[key].buildSettings.PRODUCT_NAME == `"${targetName}"`
) {
const buildSettingsObj = configurations[key].buildSettings;
buildSettingsObj.IPHONEOS_DEPLOYMENT_TARGET = "14.0";
buildSettingsObj.SWIFT_VERSION = "5.0";
buildSettingsObj.DEVELOPMENT_TEAM = props?.developmentTeamID;
buildSettingsObj.CODE_SIGN_STYLE = "Automatic";
}
}

// Add development teams to the target
xcodeProject.addTargetAttribute("DevelopmentTeam", props?.developmentTeamID, notificationServiceExtensionTarget);

return newConfig;
});
};

const withAirshipServiceExtensionPod: ConfigPlugin<AirshipIOSPluginProps> = (config, props) => {
const targetName = props.notificationServiceTargetName ?? DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME

return withPodfile(config, async (config) => {
const airshipServiceExtensionPodfileSnippet = `
target '${NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME}' do
target '${targetName}' do
use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']
use_frameworks! :linkage => ENV['USE_FRAMEWORKS'].to_sym if ENV['USE_FRAMEWORKS']
pod 'AirshipServiceExtension'
Expand Down Expand Up @@ -204,13 +218,46 @@ const withAirshipServiceExtensionPod: ConfigPlugin<AirshipIOSPluginProps> = (con
});
};

const withEasManagedCredentials: ConfigPlugin<AirshipIOSPluginProps> = (config, props) => {
assert(config.ios?.bundleIdentifier, "Missing 'ios.bundleIdentifier' in app config.")
config.extra = getEasManagedCredentialsConfigExtra(config as ExpoConfig, props);
return config;
}

function getEasManagedCredentialsConfigExtra(config: ExpoConfig, props: AirshipIOSPluginProps): {[k: string]: any} {
return {
...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: [
...(config.extra?.eas?.build?.experimental?.ios?.appExtensions ?? []),
{
// Sync up with the new target
targetName: props.notificationServiceTargetName ?? DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME,
bundleIdentifier: `${config?.ios?.bundleIdentifier}.${props.notificationServiceTargetName ?? DEFAULT_NOTIFICATION_SERVICE_EXTENSION_TARGET_NAME}`,
}
]
}
}
}
}
}
}

export const withAirshipIOS: ConfigPlugin<AirshipIOSPluginProps> = (config, props) => {
config = withCapabilities(config, props);
config = withAPNSEnvironment(config, props);
if (props.notificationService) {
config = withNotificationServiceExtension(config, props);
config = withExtensionTargetInXcodeProject(config, props);
config = withAirshipServiceExtensionPod(config, props);
config = withEasManagedCredentials(config, props);
}
return config;
};

0 comments on commit 7578cf2

Please sign in to comment.