Skip to content

feat(cli): check and register the App ID in init apns, for every setup - #2006

Closed
ArnabChatterjee20k wants to merge 12 commits into
messaging-provider-cli-apnsfrom
messaging-provider-cli-apns-appid
Closed

ArnabChatterjee20k wants to merge 12 commits into
messaging-provider-cli-apnsfrom
messaging-provider-cli-apns-appid

Conversation

@ArnabChatterjee20k

@ArnabChatterjee20k ArnabChatterjee20k commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

What does this PR do?

appwrite init apns now makes sure the app's bundle ID is registered as an App ID with Push Notifications, on every run and with every key setup (appwrite, expo, fastlane). Without that, APNs refuses every push for the bundle ID with TopicDisallowed, even though the key and the Appwrite provider look fine.

Creating a key doesn't register the App ID. Xcode only registers it for a device build with the Push Notifications capability added. Projects built only for the Simulator, using manual signing, or set up before push was added never get one. I hit this while testing #2000: a working team key, a configured provider, and TopicDisallowed on the first push.

Usage

Nothing new to remember: every init apns checks the App ID.

$ appwrite init apns
✓ APNs is already set up for com.example.app.
Checking the App ID for com.example.app ...
Using the saved Apple sign-in for dev@example.com.
? Push Notifications is off for com.example.app, so APNs refuses pushes for it. Turn it on?  Yes
✓ Turned on Push Notifications for the App ID com.example.app.

How the check signs in:

Situation What happens
A key was just created (--create-key) Reuses that sign-in, with no extra prompt (including after --reset)
A saved Apple sign-in exists Uses it without prompting
No saved sign-in Asks: Sign in with your Apple ID to check the App ID for com.example.app? Choosing "Skip" moves on with a hint
No terminal (CI) and no saved sign-in Skips with a hint; the setup still succeeds

Before any change (registering the App ID, or turning push on), it asks. If the App ID is already ready, it only reports that.

--register-app-id is the explicit form, for scripts or for skipping the questions:

$ appwrite init apns --register-app-id
✓ Registered com.example.app as an App ID with Push Notifications on team ABCDE12345.

It signs in if needed, makes the changes without asking, and fails the command if it can't. Without the flag, a failed check only warns.

How

  • PrepareAppID is now part of apns.Adapter, next to CreateKey, so every setup must implement it.
    • apns.PrepareAppID holds adapters to the same contract as apns.CreateKey: a valid bundle ID and team ID go in, and a consistent result for the right team comes out.
    • apns.ConfirmAppIDChange and apns.AppIDName give every setup the same questions and the same App ID name.
    • Request.SavedSignInOnly lets the automatic check use only a saved sign-in. Without one, the adapter returns apns.ErrSignInNeeded instead of prompting.
  • appwrite (native Go): uses the portal's services-account/v1/bundleIds API with the existing cookie session, following fastlane spaceship's web-session calls:
    • reads are POSTs with X-HTTP-Method-Override: GET;
    • creating an App ID is POST bundleIds;
    • enabling push is PATCH bundleIds/{id} with PUSH_NOTIFICATIONS.
    • The lookup matches the exact identifier, because the portal's filter also matches longer identifiers that start with the bundle ID.
  • expo: the helper gets an --action app-id mode built on apple-utils:
    • BundleId.findAsync, createAsync, hasCapabilityAsync and updateBundleIdCapabilityAsync(PUSH_NOTIFICATIONS: ON);
    • a saved-only check restores apple-utils' saved session for the Apple ID.
  • fastlane: the Fastfile gets a prepare_app_id lane built on spaceship's ConnectAPI::BundleId with the portal session:
    • a saved-only check uses spaceship's has_valid_session and never asks for a password;
    • it never offers to install fastlane.
  • Questions for expo and fastlane: the helper checks, the Go side asks, then a second run applies the change. All three setups ask the same questions.

Test Plan

  • apns: the PrepareAppID request checks and adapter contract (invalid team, wrong team, inconsistent results, ErrSignInNeeded), AppIDName, and ConfirmAppIDChange wording.
  • appwrite adapter, against the fake Apple server (which now serves services-account/v1):
    • a missing App ID is registered with push after one question;
    • push is turned on for an existing App ID;
    • a ready App ID is left unchanged;
    • declining changes nothing;
    • a longer identifier returned by the prefix filter isn't treated as a match;
    • a saved-only check without a session asks nothing and makes no sign-in requests.
  • expo and fastlane adapters, with stand-in node / fastlane:
    • without asking, it applies in one run;
    • a ready App ID is only checked;
    • check, then ask, then apply, with --reset only on the first run;
    • declining changes nothing;
    • saved-only: without an Apple ID, ErrSignInNeeded and no run; with one, the saved-only flag is passed and no password is asked;
    • fastlane never offers to install itself during a saved-only check.
  • Command:
    • a check runs after --create-key without signing in again;
    • a check with the saved sign-in runs on every init apns, already set up or not;
    • with no saved sign-in, it asks, and skips on no answer;
    • --register-app-id signs in, doesn't ask, and fails the command on error.
  • gofmt, go vet, go test ./internal/apns/... ./internal/cmd/; node --check helper.js; ruby -c Fastfile.
  • Rector, the Twig lint and the Generation suite.
  • Run against a real Apple account with each setup (io.appwrite.apnstest.native currently gets TopicDisallowed).

Related PRs and Issues

…PNs setup

APNs refuses pushes for a bundle ID (TopicDisallowed) unless the team has it registered as an App ID with Push Notifications, and creating a key does not register it. The appwrite adapter now implements apns.AppIDPreparer: with the same Apple session it looks the bundle ID up through the portal's services-account/v1 bundleIds API, registers it as an explicit iOS App ID when missing and turns on Push Notifications when off, asking first unless told not to. The requests follow fastlane spaceship's web-session calls.
After creating a key, init apns reuses the fresh Apple sign-in to check the bundle ID's App ID and offers to register it or turn on Push Notifications. --register-app-id runs the step on its own, also for a project that is already set up, makes the changes without asking and fails the command when it cannot. A setup that cannot check App IDs only warns.
@hansi-codes

hansi-codes Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

Adds bundle-ID validation and checks APNs setup selection before making provider changes. The init apns flow now gives clearer noninteractive Apple sign-in guidance, Expo setup hints include the APNs entitlement, and fastlane output is captured during saved-sign-in checks. Across the native, Expo, and fastlane adapters, the command continues to support checking and preparing the App ID and Push Notifications capability.

Latest changes: The newest commits add early bundle-ID and setup validation, improve noninteractive sign-in errors and the Expo entitlement hint, and capture fastlane output for saved-sign-in runs.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 16
File Change
src/SDK/Language/CLI.php Registers the APNs implementation and helper files in generated CLI output.
templates/cli/internal/apns/apns.go Defines shared APNs App ID preparation behavior, validation, and prompts.
templates/cli/internal/apns/apns_test.go Tests shared App ID validation, confirmation, and adapter contracts.
templates/cli/internal/apns/apnstest/apnstest.go Provides a fake adapter for App ID preparation tests.
templates/cli/internal/apns/appwrite/adapter.go Adds native App ID preparation and Apple sign-in session reuse.
templates/cli/internal/apns/appwrite/adapter_test.go Tests native key creation and App ID portal flows.
templates/cli/internal/apns/appwrite/appid.go Looks up, registers, and enables Push Notifications for native App IDs.
templates/cli/internal/apns/appwrite/auth.go Tracks the Apple ID associated with the native portal session.
templates/cli/internal/apns/expo/adapter.go Runs Expo App ID checks and changes, with saved-sign-in and reset handling.
templates/cli/internal/apns/expo/adapter_test.go Tests Expo App ID flows and saved-sign-in handling.
templates/cli/internal/apns/expo/helper/helper.js Adds Expo helper behavior for App ID lookup, registration, and push capability.
templates/cli/internal/apns/fastlane/adapter.go Runs fastlane App ID lanes and carries sign-in state through checks and changes.
templates/cli/internal/apns/fastlane/adapter_test.go Tests fastlane App ID flows and saved-sign-in handling.
templates/cli/internal/apns/fastlane/helper/Fastfile Adds a spaceship lane to inspect and prepare App IDs.
templates/cli/internal/cmd/initpush.go Integrates App ID preparation into APNs setup and improves validation and noninteractive guidance.
templates/cli/internal/cmd/initpush_test.go Tests App ID checks during setup, validation, and setup selection.
🔇 Filtered out · 1

Findings Hansi considered but did not post.

Finding Why
Protect the shared fastlane output buffer Verifier: Both streams are assigned the exact same comparable *bytes.Buffer pointer (&log) at line 212, and runner.command returns a standard *exec.Cmd (lines 372–376). os/exec explicitly handles equal Stdout/Stderr writers by sharing the output pipe and guarantees that at most one goroutine calls Write at a time. command.Run also waits for copying to finish before the buffer is inspected at lines 225–227. The alleged concurrent buffer writes do not occur.

Reviewed the commits since 7b939ef · 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 A · See the inline comments. Summary

Comment thread templates/cli/internal/apns/appwrite/appid.go Outdated
Every APNs setup now prepares App IDs: PrepareAppID joins CreateKey on apns.Adapter, and apns.PrepareAppID holds adapters to the same contract as apns.CreateKey (a valid bundle and team ID in, a consistent result for the right team out). ConfirmAppIDChange and AppIDName give every adapter the same questions and App ID name. Request.SavedSignInOnly lets a check use a saved sign-in without asking, returning ErrSignInNeeded when there is none.
The expo helper gains an app-id action on apple-utils' BundleId, and the Fastfile a prepare_app_id lane on spaceship's ConnectAPI BundleId with the portal session. Each checks the App ID first; the Go side asks, then a second run registers it and turns on Push Notifications. A saved-only check restores the setup's own saved session for the Apple ID (apple-utils' cookie file, spaceship's has_valid_session) and never asks, nor offers to install fastlane.
init apns checks the App ID whenever it runs, with any setup: right after a new key with that sign-in, else with a saved sign-in, else after asking whether to sign in (skipped without a terminal). Changes are asked about first. --register-app-id signs in when needed, changes without asking and fails the command when it cannot.
@ArnabChatterjee20k ArnabChatterjee20k changed the title feat(cli): register the App ID with Push Notifications in init apns feat(cli): check and register the App ID in init apns, for every setup Oct 12, 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 A · See the inline comments. Summary

Comment thread templates/cli/internal/cmd/initpush.go Outdated
The portal's identifier filter also returns longer identifiers that start with the bundle ID, and the lookup read only the first page of 200. With more of those, the exact App ID could be on a later page, be taken as missing, and get a duplicate create that Apple refuses. The lookup now follows links.next until it finds the exact identifier or the pages run out.
After --create-key the App ID step signed in from scratch, so the expo and fastlane setups asked for the Apple ID and password again, and fastlane once more for the change after the question. Keys now carry the Apple ID that signed in; the check right after a new key uses that saved sign-in only, and signs in again without asking only if it cannot. In the expo and fastlane setups the change after the question reuses the check's saved sign-in too.

@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

…nything

A bundle ID with spaces created APNs providers for it, and an unknown
--provider was only reported at the App ID check, after the providers
were written. Both now fail first.
…eds a terminal

The App ID check told people to pass --register-app-id even when they
had, and the expo setup failed with apple-utils' own message naming
EXPO_APPLE_ID. Every setup now names APPWRITE_APPLE_ID and
APPWRITE_APPLE_PASSWORD, as key creation already did.
Without a terminal and with no saved Apple sign-in, the check was
skipped with no reason given.
A check that only uses the saved sign-in asks nothing, but printed the
lane's log, including 'Continuing with normal login', before reporting
that it was skipped. The log is now shown only when the lane fails.
For an Expo app, init apns hinted only the background mode, while an
Xcode project also gets the aps-environment entitlement.
@ArnabChatterjee20k ArnabChatterjee20k mentioned this pull request Oct 13, 2026
3 of 4 tasks
@ArnabChatterjee20k

Copy link
Copy Markdown
Member Author

Closing in favour of #2015, which has appwrite init apns on its own branch from main, with everything from this PR and the fixes since. Splitting it from init fcm (#1956), which is blocked on permissions, lets APNs merge on its own. init push is dropped: init apns and init fcm run separately.

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