I'm trying to figure out if I can create an app extension (e.g. NotificationContentExtension) in a private pod? I don’t that’s possible because:
In my private pod project, when I'm trying to add an iOS extension, it's attempting to associate that to a bundleIdentifier. This causes at least two problems and potentially even more:
pod install
would just add a new target to my projectMy workaround is just have a subpod in my pod project, call it ContentExtensionHandler and just import that subpod in my app extension, replace the views in it and just pass events to the app extension, but I don’t think that’s a clean approach.
I've seen a few questions on SO but they're mainly about how to add pods to your app-extension. I want to do the exact opposite. Add an app-extension into my pod and then have the app-extension available when I do pod install
.
Does anyone know of a better solution for this or if Apple or Cocoapods have a specific recommendation for this?
My understanding is that you can't. Nor you should. The parent app should know of all its targets itself. And given that every App Extension's bundleId is prefixed with with the bundleId of it parent app, it would require a lot of build tool wizardly to get the bundleId
, plist
, entitlements, provisioning profile, code signing right from the pod itself.
What you should do is intercept the notification from the host app, and then based on whatever parameter you have, you pass it onto your pod's serviceExtensionHandler.
Yet still if you don't want the headache of having multiple targets in your app then you can have a single target within the parent app and use some scripts to change the all the bundleId
, plist
, entitlements, provisioning profile, code signing
The best answer I found online was written by damian-rzeszot from this gist originally written and referenced from here:
alias plistbuddy=/usr/libexec/PlistBuddy
alias codesign=/usr/bin/codesign
#
# Bundle identifier
#
set_plist_bundle_identifier() {
local bundle_identifier="$1"
local plist_file="$2"
plistbuddy \
-c "set :CFBundleIdentifier $bundle_identifier" \
"$plist_file"
}
set_appex_bundle_identifier() {
local appex_target_name="$1"
local bundle_identifier_suffix="$2"
local bundle_identifier="$PRODUCT_BUNDLE_IDENTIFIER.$bundle_identifier_suffix"
local plist_file="$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/$appex_target_name.appex/Info.plist"
set_plist_bundle_identifier "$bundle_identifier" "$plist_file"
}
#
# Bundle version
#
set_plist_bundle_version() {
local bundle_version="$1"
local plist_file="$2"
plistbuddy \
-c "set :CFBundleShortVersionString $bundle_version" \
"$plist_file"
}
get_plsit_bundle_version() {
local plist_file="$1"
plistbuddy \
-c "Print :CFBundleShortVersionString" \
"$plist_file"
}
get_app_bundle_version() {
local plist_file="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
get_plsit_bundle_version "$plist_file"
}
set_appex_bundle_version() {
local appex_target_name="$1"
local bundle_version="$2"
local plist_file="$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/$appex_target_name.appex/Info.plist"
set_plist_bundle_version "$bundle_version" "$plist_file"
}
#
# Bundle build
#
set_plist_bundle_build() {
local bundle_build="$1"
local plist_file="$2"
plistbuddy \
-c "set :CFBundleVersion $bundle_build" \
"$plist_file"
}
get_plist_bundle_build() {
local plist_file="$1"
plistbuddy \
-c "Print :CFBundleVersion" \
"$plist_file"
}
set_appex_bundle_build() {
local appex_target_name="$1"
local bundle_version="$2"
local plist_file="$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/$appex_target_name.appex/Info.plist"
set_plist_bundle_build "$bundle_version" "$plist_file"
}
get_app_bundle_build() {
local plist_file="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
get_plist_bundle_build "$plist_file"
}
#
# Code signing
#
prepare_entitlements_file() {
local appex_target_name="$1"
local bundle_identifier_suffix="$2"
local output_file="$3"
local original_entitlements="$CONFIGURATION_TEMP_DIR/$appex_target_name.build/$appex_target_name.appex.xcent"
local bundle_identifier="$DEVELOPMENT_TEAM.$PRODUCT_BUNDLE_IDENTIFIER.$bundle_identifier_suffix"
cp "$original_entitlements" "$output_file"
if [[ $CONFIGURATION == "Release" ]]
then
plistbuddy \
-c "set :application-identifier $bundle_identifier" \
"$output_file"
plistbuddy \
-c "set :keychain-access-groups:0 $bundle_identifier" \
"$output_file"
fi
}
copy_provisioning_profile() {
local appex_target_name="$1"
local provision_source="$2"
local provision_destination="$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/$appex_target_name.appex/$EMBEDDED_PROFILE_NAME"
cp "$provision_source" "$provision_destination"
}
resign_appex() {
local appex_target_name="$1"
local entitlements_file="$2"
codesign \
--force \
--sign "$EXPANDED_CODE_SIGN_IDENTITY" \
--entitlements "$entitlements_file" \
--timestamp=none \
"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/$BUNDLE_PLUGINS_FOLDER_PATH/$appex_target_name.appex"
}
#
#
#
#
#
set_appex_bundle_identifier \
"NotificationService" \
"notification-service"
set_appex_bundle_version \
"NotificationService" \
`get_app_bundle_version`
set_appex_bundle_build \
"NotificationService" \
`get_app_bundle_build`
# Be careful if using `keychain-access-groups` entitlement
prepare_entitlements_file \
"NotificationService" \
"notification-service" \
"$DERIVED_SOURCES_DIR/NotificationService-Entitlements.plist"
copy_provisioning_profile \
"NotificationService" \
"$SOURCE_ROOT/../.github/appstore/$TARGET_NAME/profiles/notification-service.mobileprovision"
resign_appex \
"NotificationService" \
"$DERIVED_SOURCES_DIR/NotificationService-Entitlements.plist"