Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/actions/create-demo-env/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Create demo .env"
description: "Writes the Unity demo app's .env file used by E2E builds"
inputs:
onesignal-app-id:
description: "OneSignal App ID for the demo app"
required: true
onesignal-api-key:
description: "OneSignal REST API key for the demo app"
required: true
onesignal-android-channel-id:
description: "Android Notification Channel ID used by the WITH SOUND test notification"
required: false
default: "7ec2ece9-c538-4656-9516-1316f48a005c"
e2e-mode:
description: "Whether to enable E2E_MODE in the demo app"
required: false
default: "true"
runs:
using: "composite"
steps:
- name: Write .env
working-directory: examples/demo
shell: bash
env:
APP_ID: ${{ inputs.onesignal-app-id }}
API_KEY: ${{ inputs.onesignal-api-key }}
ANDROID_CHANNEL_ID: ${{ inputs.onesignal-android-channel-id }}
E2E_MODE: ${{ inputs.e2e-mode }}
run: |
{
echo "ONESIGNAL_APP_ID=$APP_ID"
echo "ONESIGNAL_API_KEY=$API_KEY"
echo "ONESIGNAL_ANDROID_CHANNEL_ID=$ANDROID_CHANNEL_ID"
echo "E2E_MODE=$E2E_MODE"
} > .env
Comment thread
fadi-george marked this conversation as resolved.
234 changes: 234 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
name: E2E Tests

on:
push:
branches:
- rel/**
workflow_dispatch:
inputs:
platform:
description: "Platform to test"
required: true
default: "both"
type: choice
options:
- android
- ios
- both

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-android:
if: >-
github.event_name == 'push' ||
github.event.inputs.platform == 'android' ||
github.event.inputs.platform == 'both'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true

- name: Create demo .env
uses: ./.github/actions/create-demo-env
with:
onesignal-app-id: ${{ vars.APPIUM_ONESIGNAL_APP_ID }}
onesignal-api-key: ${{ secrets.APPIUM_ONESIGNAL_API_KEY }}

- name: Resolve OneSignal Android SDK version
id: android-sdk-version
run: |
VERSION=$(grep -oE 'com\.onesignal:OneSignal:[^"]+' com.onesignal.unity.android/Editor/OneSignalAndroidDependencies.xml | head -n1 | cut -d: -f3)
if [ -z "$VERSION" ]; then
echo "::error::Could not parse OneSignal Android SDK version from OneSignalAndroidDependencies.xml"
exit 1
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Wait for OneSignal Android SDK on Maven Central
uses: OneSignal/sdk-shared/.github/actions/wait-for-maven-artifact@main
with:
version: ${{ steps.android-sdk-version.outputs.version }}

- name: Cache Unity Library
uses: actions/cache@v5
with:
path: examples/demo/Library
key: unity-library-android-${{ hashFiles('examples/demo/Packages/manifest.json', 'examples/demo/ProjectSettings/ProjectVersion.txt') }}
restore-keys: unity-library-android-

- name: Build APK
uses: game-ci/unity-builder@v4
env:
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_EMAIL: ${{ secrets.UNITY_USERNAME }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: examples/demo
unityVersion: auto
targetPlatform: Android
buildMethod: BuildScript.BuildAndroidEmulator
allowDirtyBuild: true

- name: Upload APK
uses: actions/upload-artifact@v7
with:
name: demo-apk
path: examples/demo/Build/Android/onesignal-demo.apk
retention-days: 1
compression-level: 0

build-ios:
if: >-
github.event_name == 'push' ||
github.event.inputs.platform == 'ios' ||
github.event.inputs.platform == 'both'
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
lfs: true

- name: Create demo .env
uses: ./.github/actions/create-demo-env
with:
onesignal-app-id: ${{ vars.APPIUM_ONESIGNAL_APP_ID }}
onesignal-api-key: ${{ secrets.APPIUM_ONESIGNAL_API_KEY }}

- name: Cache Unity Library
uses: actions/cache@v5
with:
path: examples/demo/Library
key: unity-library-ios-${{ hashFiles('examples/demo/Packages/manifest.json', 'examples/demo/ProjectSettings/ProjectVersion.txt') }}
restore-keys: unity-library-ios-

- name: Cache Xcode DerivedData
# Hash inputs to the Unity iOS export (files that exist at checkout
# time) rather than the exported Xcode project / Podfile, which
# don't exist until later steps run. Mirrors the Android Unity
# Library cache key shape above.
uses: actions/cache@v5
with:
path: examples/demo/Build/iOS-DerivedData
key: deriveddata-${{ runner.os }}-${{ hashFiles('examples/demo/Packages/manifest.json', 'examples/demo/ProjectSettings/ProjectVersion.txt', 'examples/demo/ProjectSettings/ProjectSettings.asset', 'com.onesignal.unity.ios/Editor/**', 'com.onesignal.unity.core/Editor/**', 'examples/demo/iOS/ExportOptions.plist') }}
restore-keys: deriveddata-${{ runner.os }}-
Comment thread
fadi-george marked this conversation as resolved.

- name: Export Xcode project from Unity
uses: game-ci/unity-builder@v4
env:
UNITY_SERIAL: ${{ secrets.UNITY_SERIAL }}
UNITY_EMAIL: ${{ secrets.UNITY_USERNAME }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
projectPath: examples/demo
unityVersion: auto
targetPlatform: iOS
buildMethod: BuildScript.BuildiOSDevice
allowDirtyBuild: true
cacheUnityInstallationOnMac: true

- name: Pod install
working-directory: examples/demo/Build/iOS
run: pod install --repo-update

- name: Set up iOS codesigning
uses: OneSignal/sdk-shared/.github/actions/setup-ios-demo-codesigning@main
with:
p12-base64: ${{ secrets.APPIUM_IOS_DEV_CERT_P12_BASE64 }}
p12-password: ${{ secrets.APPIUM_IOS_DEV_CERT_PASSWORD }}
asc-key-id: ${{ secrets.APPIUM_APP_STORE_CONNECT_KEY_ID }}
asc-issuer-id: ${{ secrets.APPIUM_APP_STORE_CONNECT_ISSUER_ID }}
asc-private-key: ${{ secrets.APPIUM_APP_STORE_CONNECT_PRIVATE_KEY }}

- name: Build signed IPA
working-directory: examples/demo/Build/iOS
# Unity always names the generated Xcode project Unity-iPhone, even
# though the demo's product name is "OneSignal Demo". After
# `pod install` an Unity-iPhone.xcworkspace exists and must be used;
# without CocoaPods we fall back to the .xcodeproj. The
# SigningPostProcessor already pinned DEVELOPMENT_TEAM and the NSE /
# Live Activity bundle IDs to match ExportOptions.plist.
run: |
if [ -d Unity-iPhone.xcworkspace ]; then
CONTAINER_ARGS=(-workspace Unity-iPhone.xcworkspace)
else
CONTAINER_ARGS=(-project Unity-iPhone.xcodeproj)
fi
xcodebuild archive \
"${CONTAINER_ARGS[@]}" \
-scheme Unity-iPhone \
-configuration Release \
-sdk iphoneos \
-destination 'generic/platform=iOS' \
-archivePath build/App.xcarchive \
-derivedDataPath ../iOS-DerivedData \
-quiet \
-hideShellScriptEnvironment \
CODE_SIGN_STYLE=Manual \
COMPILER_INDEX_STORE_ENABLE=NO
xcodebuild -exportArchive \
-archivePath build/App.xcarchive \
-exportOptionsPlist "$GITHUB_WORKSPACE/examples/demo/iOS/ExportOptions.plist" \
-exportPath build/ipa \
-quiet

- name: Locate and stage IPA
id: ipa
working-directory: examples/demo
run: |
IPA=$(ls Build/iOS/build/ipa/*.ipa | head -n1)
if [ -z "$IPA" ]; then
echo "::error::No IPA produced by xcodebuild -exportArchive"
exit 1
fi
cp "$IPA" demo.ipa
echo "path=examples/demo/demo.ipa" >> "$GITHUB_OUTPUT"

- name: Verify aps-environment in IPA
working-directory: examples/demo
run: |
unzip -oq demo.ipa -d /tmp/ipa
APP=$(ls -d /tmp/ipa/Payload/*.app | head -n1)
codesign -d --entitlements - "$APP" 2>&1 | tee /tmp/entitlements.txt
if ! grep -q 'aps-environment' /tmp/entitlements.txt; then
echo "::error::Built IPA is missing aps-environment entitlement; push subscription will not work"
exit 1
fi

- name: Upload IPA
uses: actions/upload-artifact@v7
with:
name: demo-ipa
path: ${{ steps.ipa.outputs.path }}
retention-days: 1
compression-level: 0

e2e-android:
needs: build-android
uses: OneSignal/sdk-shared/.github/workflows/appium-e2e.yml@main
secrets: inherit
with:
platform: android
app-artifact: demo-apk
app-filename: onesignal-demo.apk
sdk-type: unity
build-name: unity-android-${{ github.ref_name }}-${{ github.run_number }}

e2e-ios:
needs: build-ios
uses: OneSignal/sdk-shared/.github/workflows/appium-e2e.yml@main
secrets: inherit
with:
platform: ios
app-artifact: demo-ipa
app-filename: demo.ipa
sdk-type: unity
build-name: unity-ios-${{ github.ref_name }}-${{ github.run_number }}
43 changes: 43 additions & 0 deletions examples/demo/Assets/Scripts/Editor/BuildScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,49 @@ public static void BuildiOSSimulator()
HandleReport(report, IOSOutputDir);
}

/// <summary>
/// Builds an Xcode project targeting physical iOS devices, used by CI to
/// produce a signed IPA for BrowserStack. The OneSignal SDK and demo
/// post-processors add push capabilities, the NSE / Live Activity widget
/// targets, and pin DEVELOPMENT_TEAM + aps-environment=development so the
/// archive step can sign with the Appium provisioning profiles in
/// ExportOptions.plist.
/// </summary>
public static void BuildiOSDevice()
{
Directory.CreateDirectory(IOSOutputDir);

PlayerSettings.SetScriptingBackend(NamedBuildTarget.iOS, ScriptingImplementation.IL2CPP);
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;

Debug.Log(
$"[BuildScript] iOS sdk={PlayerSettings.iOS.sdkVersion} backend={PlayerSettings.GetScriptingBackend(NamedBuildTarget.iOS)}"
);

PlayerSettings.SetIl2CppCodeGeneration(
NamedBuildTarget.iOS,
Il2CppCodeGeneration.OptimizeSize
);
PlayerSettings.SetManagedStrippingLevel(NamedBuildTarget.iOS, ManagedStrippingLevel.High);
PlayerSettings.stripEngineCode = true;

PlayerSettings.SetIl2CppCompilerConfiguration(
NamedBuildTarget.iOS,
Il2CppCompilerConfiguration.Release
);

var options = new BuildPlayerOptions
{
scenes = GetScenes(),
locationPathName = IOSOutputDir,
target = BuildTarget.iOS,
options = BuildOptions.None,
};

var report = BuildPipeline.BuildPlayer(options);
HandleReport(report, IOSOutputDir);
}

private static string[] GetScenes()
{
var scenes = EditorBuildSettings.scenes;
Expand Down