Skip to content

feat(cli): appwrite init apns - #2015

Merged
ArnabChatterjee20k merged 11 commits into
mainfrom
messaging-provider-cli-init-apns
Oct 15, 2026
Merged

ArnabChatterjee20k merged 11 commits into
mainfrom
messaging-provider-cli-init-apns

Conversation

@ArnabChatterjee20k

@ArnabChatterjee20k ArnabChatterjee20k commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

What does this PR do?

Adds appwrite init apns, which sets up Appwrite Push for an iOS app. It creates the APNs providers, sets up the Xcode project, checks the App ID with Apple, and, if wanted, creates the APNs key itself by signing in with the Apple ID.

It's the APNs half of #1963 and #2006, on its own branch from main, so it can merge without the FCM work. init fcm (#1956) is blocked on permissions and stays separate. There's no init push; the two commands run separately.

What's in it

appwrite init apns Creates or updates the APNs production and sandbox providers for an iOS app. Adds the aps-environment entitlement and the remote-notification background mode to the Xcode target.
Apple platform Adds an Apple platform for the bundle ID to the project when it has none: without one, the API refuses the app's requests, device registration included, as an unknown origin. If it can't, it says how to add it in the console.
Next steps Ends with what init apns doesn't set up: the Appwrite push provider when the project has none enabled (messages travel over it; APNs only wakes the app), and the Notification Service Extension with its App Group, for delivery while the app is in the background or swiped away.
App ID check Every run checks that the bundle ID is an App ID with Push Notifications on the team, since APNs refuses pushes for any other bundle ID (TopicDisallowed). It uses a key's fresh sign-in or a saved one, and asks before signing in or changing anything. --register-app-id makes the changes without asking.
--create-key Creates the APNs key by signing in with the Apple ID (password, two-factor), with no trip to the Apple Developer portal. Experimental.
Setups Three interchangeable ways to talk to Apple: appwrite (native Go, the default), expo (@expo/apple-utils) and fastlane (spaceship). Picked with --provider or APPWRITE_APNS_SETUP. If Apple's private API breaks one, users switch instead of waiting for a release.

Usage

iOS app with a key in the project folder

appwrite init apns

The bundle ID and team come from the Xcode project or app.json, and the key ID from the AuthKey_<KEYID>.p8 file name, so nothing is asked:

ℹ Info: Setting up APNs ...
✓ Success: Created provider APNs (io.appwrite.apnstest.native) ( … )
✓ Success: Created provider APNs sandbox (io.appwrite.apnstest.native) ( … )
✓ Success: Added aps-environment to APNsNative/APNsNative.entitlements
✓ Success: Added the remote-notification background mode to APNsNative/Info.plist
✓ Success: APNs is set up for io.appwrite.apnstest.native.
✓ Success: Added the Apple platform io.appwrite.apnstest.native to the project.
ℹ Info: Checking the App ID for io.appwrite.apnstest.native ...
✓ Success: io.appwrite.apnstest.native is registered as an App ID with Push Notifications.
♥ Hint: For messages while the app is in the background or swiped away, add a Notification Service Extension whose class extends AppwriteNotificationService, and put the app and the extension in one App Group, named by AppwritePushAppGroup in both Info.plists.

A key you already have

appwrite init apns --key-path ~/keys/AuthKey_Q4GAU66T2N.p8 --team-id ABCDE12345

Create the key with the Apple ID

appwrite init apns --create-key                      # appwrite setup
appwrite init apns --create-key --provider fastlane  # or expo
  • The sign-in is saved in ~/.appwrite/apns/<setup>/ (0600). Later runs skip the password and two-factor until Apple expires it.
  • Without --create-key, the same option is offered when no key is found, next to creating the key in the browser or picking a file.

Only one environment

appwrite init apns --environment sandbox

Register the App ID without being asked

appwrite init apns --register-app-id

Without a terminal (CI)

APPWRITE_APPLE_ID and APPWRITE_APPLE_PASSWORD answer the Apple ID and password, but the two-factor code always needs a terminal. In CI, pass --key-path. The App ID check then reports that it was skipped and why, and doesn't fail the command unless --register-app-id was passed.

Flags

Flag Meaning When omitted
--bundle-id <id> iOS bundle ID; letters, digits, hyphens and dots PRODUCT_BUNDLE_IDENTIFIER of the app target, or Expo ios.bundleIdentifier. With several apps, a picker; with none, asked.
--team-id <id> 10-character Apple Developer team ID The target's DEVELOPMENT_TEAM, Expo ios.appleTeamId, or the team on an existing provider. With --create-key, the Apple sign-in picks it.
--key-path <file> An existing APNs auth key (.p8) A valid .p8 in the project folder. Otherwise asked: create one with the Apple ID, create it in the browser, or use a file.
--key-id <id> 10-character key ID From the AuthKey_<KEYID>.p8 file name, otherwise asked. A created key uses Apple's ID.
--create-key Create the key by signing in with the Apple ID Offered when no key is found
--provider <setup> appwrite, expo or fastlane $APPWRITE_APNS_SETUP, then appwrite
--environment <env> production, sandbox or all all
--reset Sign in to Apple again instead of reusing the saved sign-in (implies --create-key) The saved sign-in is reused
--register-app-id Register the App ID and turn on Push Notifications without asking; fail if that can't be done Checked on every run, and asked before any change
--force (global) Replace the key on providers that are already set up A rerun says "already set up" and only checks the App ID

--create-key and --reset can't be combined with --key-path or --key-id.

Variable Meaning
APPWRITE_APNS_SETUP Default setup (appwrite, expo, fastlane)
APPWRITE_APPLE_ID Answers the Apple ID question. The CLI prints the variable's name, never its value.
APPWRITE_APPLE_PASSWORD Answers the password question, likewise never printed

Test Plan

  • go vet, gofmt and go test for the whole generated CLI, including the internal/apns setups and the init apns tests; the Generation suite, Rector and Twig lint.
  • Against a real local Appwrite, run on native Xcode, fastlane and Expo sample projects, with each of the three setups.
    • Results: detection, sandbox-only and both-environment setups, re-runs updating providers without duplicates, and the Xcode edits all work.

    • Bad input:

      • malformed --bundle-id, --team-id or --key-id;
      • a missing or non-.p8 key;
      • an unknown --provider or --environment;
      • clashing flags.

      Each fails before anything is written.

    • Without a terminal: all three setups give the same message.

  • Creating keys, and the App ID check and registration, against a real Apple account (in feat(cli): init apns and init push, with one-click APNs key creation #1963 and feat(cli): check and register the App ID in init apns, for every setup #2006).
  • Each setup's App ID check again on a fresh sign-in. The saved Apple sign-ins used for testing have expired.

Related PRs and Issues

The appwrite (native Go), expo (apple-utils) and fastlane (spaceship)
setups behind one apns.Adapter: each signs in to the Apple Developer
portal, creates an APNs key, and checks or registers the App ID with Push
Notifications.
Sets up the APNs providers (sandbox and production) for an iOS app from
an existing .p8 or one created by signing in with the Apple ID, detects
the bundle ID and team from an Xcode project or Expo config, adds
aps-environment and the remote-notification background mode, and checks
the App ID on every run.
@hansi-codes

hansi-codes Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

Adds appwrite init apns to the generated CLI, with Xcode project updates, APNs provider setup, App ID checks, and optional Apple sign-in/key creation through native, Expo, or fastlane adapters. It also adds adapter and command tests, plus end-to-end coverage against persistent Appwrite and Apple API mocks. The latest changes extend that harness to cover Apple sign-in, key creation, and App ID registration and updates.

Latest changes: The newest commits add persistent mock Apple sign-in and Developer portal endpoints, inject mock hosts only into the CLI E2E build, and exercise saved sign-in, App ID registration and Push activation, and the key limit.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 6
File Change
src/SDK/Language/CLI.php; templates/cli/internal/cmd/init.go Registers and exposes the generated init apns CLI command.
templates/cli/internal/cmd/initpush.go; templates/cli/internal/cmd/initpushdetect.go; templates/cli/internal/cmd/initpush_test.go Implements APNs setup, project detection and updates, App ID handling, and command tests.
templates/cli/internal/apns/** Adds APNs setup interfaces, validation, tests, and native, Expo, and fastlane Apple setup adapters and helpers.
mock-server/app/http.php Adds persistent mock state and mock Appwrite and Apple APIs for APNs end-to-end tests.
tests/e2e/CLIGo126Test.php; tests/e2e/languages/cli/applehosts.go; tests/e2e/languages/cli/main.go Extends CLI end-to-end coverage through mock Apple sign-in, key creation, and App ID preparation.
src/SDK/Language/CLI.php Registers the new APNs command, adapters, helpers, and tests in generated CLI output.

Reviewed the commits since 758419f · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

…h needs

Without an Apple platform for the bundle ID the API refuses the app's
requests as an unknown origin, device registration included, and init
apns left that to the console. It now adds the platform when the project
has none for the bundle ID, and tells how to add it when it can't.

It also ends with what init apns doesn't set up: the Appwrite push
provider when the project has none enabled, and the Notification Service
Extension with its App Group for background and swiped-away delivery.
hansi-codes[bot]
hansi-codes Bot previously requested changes Oct 14, 2026

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Tier B · 1 blocking finding to address. Summary

Comment thread templates/cli/internal/cmd/initpush.go
@hansi-codes
hansi-codes Bot dismissed their stale review October 14, 2026 08:24

The findings that requested changes are resolved. See the summary comment for what is still open.

The mock API keeps messaging providers and project platforms per
project, so the harness can run the built binary on a project folder:
the first run creates both APNs providers and the Apple platform and
prints the next steps, a rerun changes nothing, and a malformed bundle
ID, an unknown --provider and an unknown --environment fail.

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Tier A · See the inline comments. Summary

Comment thread tests/e2e/languages/cli/main.go Outdated
ArnabChatterjee20k and others added 7 commits October 14, 2026 16:04
The mock keeps providers and platforms in a volume that docker compose
down leaves in place, so a fixed project made every run after the first
see the earlier run's providers and fail its first-run checks.
…PLE_HOST

The e2e tests run init apns against a mock of Apple, so the sign-in,
App Store Connect and Developer portal hosts can all be set to one base
URL. Unset, they stay Apple's servers.
The mock API gains Apple's sign-in, session, team, key and App ID
endpoints under /apple, kept per Apple ID. The harness signs in with an
Apple ID and password, creates the key and registers the App ID, then
reuses the saved sign-in to check the App ID on a rerun, turn on Push
Notifications for an existing App ID, and create keys until the team has
no free slot.
…ns-apple-e2e

test(cli): e2e for init apns against a mock of Apple
APPWRITE_APPLE_HOST could send an Apple ID and password to any server
from the shipped CLI. It now lives in a file built only with the e2e
tag, which the CLI e2e suite passes; release builds always talk to
Apple.
The override is no longer generated into the SDK. Like the conformance
harness, it lives under tests/e2e/languages/cli and CLIGo126Test copies
it into the generated CLI before building, so released SDKs never
contain it.
…ns-e2e

test(cli): e2e for init apns against the mock API and a mock of Apple

@hansi-codes hansi-codes Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Tier S · Looks good to merge. Summary

@ArnabChatterjee20k
ArnabChatterjee20k merged commit 84360d2 into main Oct 15, 2026
61 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant