Skip to content

fix(android): unblock build + JNI bridge for the default Android target#1159

Merged
proggeramlug merged 1 commit into
PerryTS:mainfrom
proggeramlug:android-visual-fixes
May 20, 2026
Merged

fix(android): unblock build + JNI bridge for the default Android target#1159
proggeramlug merged 1 commit into
PerryTS:mainfrom
proggeramlug:android-visual-fixes

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

Summary

Bringing up a Perry-targeted app on the Android emulator from current
main surfaced a chain of breakages — the Android target wasn't
compilable, dlopenable, or runnable end-to-end. None of these changes
are Android-specific behavior tweaks; each one repairs a contract that
other platforms already honor.

Verified on a Pixel_8 emulator (API 35, arm64-v8a, NDK 30): app now
compiles cleanly, links cleanly, passes dlopen, runs Java_…_nativeMain
through to App.run()/setContentView, and starts the 8 ms timer pump.

Compile / link fixes

File Fix
crates/perry-ui-android/src/lib.rs (perry_system_take_screenshot) Function referenced crate::screenshot::… unconditionally but pub mod screenshot; is #[cfg(feature = \"geisterhand\")]. Default builds failed with E0433. Cfg-gate the function; non-geisterhand returns an empty base64 string, matching the documented contract.
crates/perry-ui-android/src/lib.rs Added no-op perry_ui_lazyvstack_set_row_height (matches the iOS stub). Without it, every app that calls lazyvstackSetRowHeight(list, …) failed dlopen(libperry_app.so) with cannot locate symbol.
crates/perry-runtime/src/gc.rs Added no-op js_gc_note_slot_layout / js_gc_write_barriers_emitted. The codegen emits unconditional refs; no crate provided them, so dlopen died on the first. No-op honors the contract (the GC functions fine without per-slot layout notes).
android-build/.../PerryBridge.kt (granted expression) Kotlin syntax error: == / || at line start. Moved operators to line ends.
android-build/.../PerryBridge.kt (richTextToggleSpan) Kotlin 2.0.21 rejects inline fun lambdas called from inside uiHandler.post { … } without crossinline. Added on factory and matches.
android-build/.../PerryBridge.kt (nativeNotification{Tap,Token,Receive,BackgroundReceive}) Added the four @JvmStatic external fun declarations. PerryFirebaseMessagingService / PerryNotificationReceiver referenced them; the Rust side already exports the matching JNI symbols in perry-ui-android/src/system.rs.

JNI-bridge fixes

Area Fix
crates/perry-ui-android/src/widgets/securefield.rs Called PerryBridge.setTextWatcher but the actual entrypoint is setTextChangedCallback (textfield.rs / textarea.rs use it). Mismatch aborted with JNI DETECTED ERROR … NoSuchMethodError the moment a SecureField was constructed. Renamed the JNI call to match.
android-build/.../PerryBridge.kt (deep links) The Kotlin side had no deep-link implementation. perry-ui-android/src/deeplinks.rs documents the contract: register a handler key via PerryBridge.appOnOpenUrl(J)V, read the cold-start URL via appGetLaunchUrl()Ljava/lang/String;, dispatch URLs back into JS through nativeInvokeDeepLinkCallback(key, url, source). None existed. set_handler() discards the JNI result, so the NoSuchMethodError exception stayed pending and the next JNI op (NewLocalRef from NavStack get_activity) tripped CheckJNI → app abort. Added: appOnOpenUrl / appGetLaunchUrl / deliverDeepLinkUrl @JvmStatic methods + the external fun nativeInvokeDeepLinkCallback declaration on PerryBridge.
android-build/.../PerryActivity.kt Captures intent?.data in onCreate (cold start) and overrides onNewIntent (warm), routing both through PerryBridge.deliverDeepLinkUrl(url, source).

Known follow-up — not in this PR

After all of the above the app passes dlopen, nativeMain runs to
completion, the NavStack tree is built, root view is attached, and the
8 ms timer pump starts. ~140 ms later the first JS-side callback fires
and the HWUI worker aborts with:

F libc    : FORTIFY: pthread_mutex_lock called on a destroyed mutex (0x...)
F libc    : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid N (hwuiTask1)

No tombstone is produced (FORTIFY aborts skip the standard debuggerd
dump path), no Java exception, no JNI message. Likely a render-side
use-after-free of a sync primitive — needs lldb / ASAN to localize.
Filing as a separate issue.

Test plan

  • cargo build --release -p perry-ui-android -p perry-runtime --target aarch64-linux-android (NDK 30, with the cc-rs unversioned-clang shim documented in the issue tracker) — clean build
  • perry compile src/main.ts --target android -o libperry_app.so — links, no missing symbols
  • cd android-build && ./gradlew assembleDebugBUILD SUCCESSFUL, APK produced
  • adb install + am start — no UnsatisfiedLinkError, no JNI NoSuchMethodError, no perry-native-thread tombstone; reaches attach_root_to_activity: setContentView called + start_timer_pump
  • Visual audit on emulator — blocked by the HWUI mutex abort (separate issue)

Discovered while bringing up a Perry-targeted app on the Android emulator
from `main` — the Android target wasn't compilable, dlopenable, or
runnable end-to-end. None of the changes here are Android-specific
behavior tweaks; each one repairs a contract that other platforms
already honor.

## Build (compile-time)

- `perry-ui-android` `perry_system_take_screenshot` referenced
  `crate::screenshot` unconditionally, but `pub mod screenshot;` is
  `#[cfg(feature = "geisterhand")]`. Default builds failed with
  `E0433: cannot find 'screenshot' in 'crate'`. Cfg-gate the function:
  return an empty base64 string when geisterhand is off, matching the
  documented "returns empty string if capture is unavailable" contract.

- `PerryBridge.kt` `granted` expression had `==` / `||` at line *start*
  (invalid Kotlin) — fixed by moving operators to line ends.

- `richTextToggleSpan`'s inline-fun `factory: () -> T` and
  `matches: (T) -> Boolean` lambdas were called from inside
  `uiHandler.post { ... }`. Kotlin 2.0.21 rejects this without
  `crossinline`. Added.

- `PerryFirebaseMessagingService` / `PerryNotificationReceiver`
  referenced four `nativeNotification*` externs that didn't exist on
  PerryBridge. Added matching `@JvmStatic external fun` declarations
  (the Rust side already exports the JNI symbols in `system.rs`).

## Link / dlopen

- `perry-ui-android` didn't export `perry_ui_lazyvstack_set_row_height`;
  every Perry app that calls `lazyvstackSetRowHeight(list, …)` therefore
  failed `dlopen(libperry_app.so)` at launch with
  `cannot locate symbol "perry_ui_lazyvstack_set_row_height"`. Added a
  no-op stub matching the iOS one.

(The original branch also stubbed `js_gc_note_slot_layout` /
`js_gc_write_barriers_emitted` as no-ops to unblock `dlopen`; PerryTS#1146 has
since landed real implementations of both on `main`, so the stubs were
dropped during this rebase.)

## JNI bridge (runtime)

- `perry-ui-android/src/widgets/securefield.rs` called
  `PerryBridge.setTextWatcher`, but the actual Kotlin entrypoint is
  `setTextChangedCallback` (textfield.rs / textarea.rs already use it).
  The mismatch aborted with `JNI DETECTED ERROR ... NoSuchMethodError`
  the moment a SecureField was constructed. Renamed the JNI call.

- Deep-link bridge (`perry-ui-android/src/deeplinks.rs` is the spec
  comment) had no Kotlin implementation: `appOnOpenUrl(J)V`,
  `appGetLaunchUrl()Ljava/lang/String;`, and
  `nativeInvokeDeepLinkCallback` were all missing. Since
  `set_handler()` discards the JNI result, the `NoSuchMethodError`
  exception stayed pending and the next JNI call (NewLocalRef from
  NavStack `get_activity`) tripped CheckJNI and aborted. Added the
  three Kotlin entrypoints + the `external fun
  nativeInvokeDeepLinkCallback` declaration on `PerryBridge`, plus
  cold-start (`onCreate`) and warm (`onNewIntent`) intent.data capture
  on `PerryActivity` that funnels through `deliverDeepLinkUrl`.
@proggeramlug proggeramlug force-pushed the android-visual-fixes branch from 109d817 to e9394f2 Compare May 20, 2026 09:22
proggeramlug added a commit that referenced this pull request May 20, 2026
…nce widget build path

#1138: extract @perryts/google-auth to standalone npm package + real SDK
integration. The v0.5.847 MVP shipped the binding as
crates/perry-ext-google-auth with all three FFI entry points resolving
"not-yet-implemented" on every platform — downstream (GSC Master)
couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit /
play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK
(iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin
bridge over androidx.credentials CredentialManager + GetGoogleIdOption
(Android, via JNI from crate-android using a new perry_android_jvm()
weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
  - removed crates/perry-ext-google-auth/, types/perry/google-auth/,
    test_google_auth_compile.ts, well_known_bindings.toml entry,
    native_table.rs NativeModSig rows, runtime_decls.rs declarations,
    api-manifest entries — the npm package's nativeLibrary.functions
    drives codegen ffi_signatures, same path as other @perryts/* deps.
  - inject_google_auth_info_plist writes GIDClientID / GIDServerClientID
    / GIDDefaultScopes from [google_auth] in perry.toml into the iOS
    Info.plist.
  - inject_google_auth_android_resources writes
    res/values/google_auth.xml's google_auth_server_client_id from
    [google_auth] for the Android Kotlin bridge to read.
  - wire_native_lib_kotlin_sources is a general resolver: scans
    node_modules for perry.nativeLibrary.targets.android.kotlin_sources
    + gradle_dependencies and merges them into the Gradle project.
  - perry-ui-android's PerryActivity.onCreate reflection-calls
    PerryGoogleAuth.install(this) when the class is on the classpath
    (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a
glance_source field used to warn-and-skip ("Android Glance build path
not yet wired — follow-up issue #676 (Glance)."). Now wired:
build_declared_widgets_android in widget_build.rs mirrors the iOS
slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/,
emits res/xml/widget_info_<name>.xml, and injects a <receiver> block
into AndroidManifest.xml's <application>. Called from
build_and_run_android after the deeplinks injection + [google_auth]
Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014:
http::__get_statusMessage and http::__get_headers had no API_MANIFEST
counterpart for IncomingMessage. The test
every_dispatch_entry_has_manifest_counterpart was failing on every PR
opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two
missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes
4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device
sign-in + widget render not exercised in this session —
Ralph/downstream-GSC-Master will validate against real iOS device +
Android emulator next.

Closes #1138, closes #1139.
proggeramlug added a commit that referenced this pull request May 20, 2026
…nce widget build path

#1138: extract @perryts/google-auth to standalone npm package + real SDK
integration. The v0.5.847 MVP shipped the binding as
crates/perry-ext-google-auth with all three FFI entry points resolving
"not-yet-implemented" on every platform — downstream (GSC Master)
couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit /
play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK
(iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin
bridge over androidx.credentials CredentialManager + GetGoogleIdOption
(Android, via JNI from crate-android using a new perry_android_jvm()
weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
  - removed crates/perry-ext-google-auth/, types/perry/google-auth/,
    test_google_auth_compile.ts, well_known_bindings.toml entry,
    native_table.rs NativeModSig rows, runtime_decls.rs declarations,
    api-manifest entries — the npm package's nativeLibrary.functions
    drives codegen ffi_signatures, same path as other @perryts/* deps.
  - inject_google_auth_info_plist writes GIDClientID / GIDServerClientID
    / GIDDefaultScopes from [google_auth] in perry.toml into the iOS
    Info.plist.
  - inject_google_auth_android_resources writes
    res/values/google_auth.xml's google_auth_server_client_id from
    [google_auth] for the Android Kotlin bridge to read.
  - wire_native_lib_kotlin_sources is a general resolver: scans
    node_modules for perry.nativeLibrary.targets.android.kotlin_sources
    + gradle_dependencies and merges them into the Gradle project.
  - perry-ui-android's PerryActivity.onCreate reflection-calls
    PerryGoogleAuth.install(this) when the class is on the classpath
    (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a
glance_source field used to warn-and-skip ("Android Glance build path
not yet wired — follow-up issue #676 (Glance)."). Now wired:
build_declared_widgets_android in widget_build.rs mirrors the iOS
slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/,
emits res/xml/widget_info_<name>.xml, and injects a <receiver> block
into AndroidManifest.xml's <application>. Called from
build_and_run_android after the deeplinks injection + [google_auth]
Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014:
http::__get_statusMessage and http::__get_headers had no API_MANIFEST
counterpart for IncomingMessage. The test
every_dispatch_entry_has_manifest_counterpart was failing on every PR
opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two
missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes
4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device
sign-in + widget render not exercised in this session —
Ralph/downstream-GSC-Master will validate against real iOS device +
Android emulator next.

Closes #1138, closes #1139.
@proggeramlug proggeramlug merged commit 3d98c78 into PerryTS:main May 20, 2026
9 checks passed
proggeramlug added a commit that referenced this pull request May 20, 2026
…nce widget build path

#1138: extract @perryts/google-auth to standalone npm package + real SDK
integration. The v0.5.847 MVP shipped the binding as
crates/perry-ext-google-auth with all three FFI entry points resolving
"not-yet-implemented" on every platform — downstream (GSC Master)
couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit /
play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK
(iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin
bridge over androidx.credentials CredentialManager + GetGoogleIdOption
(Android, via JNI from crate-android using a new perry_android_jvm()
weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
  - removed crates/perry-ext-google-auth/, types/perry/google-auth/,
    test_google_auth_compile.ts, well_known_bindings.toml entry,
    native_table.rs NativeModSig rows, runtime_decls.rs declarations,
    api-manifest entries — the npm package's nativeLibrary.functions
    drives codegen ffi_signatures, same path as other @perryts/* deps.
  - inject_google_auth_info_plist writes GIDClientID / GIDServerClientID
    / GIDDefaultScopes from [google_auth] in perry.toml into the iOS
    Info.plist.
  - inject_google_auth_android_resources writes
    res/values/google_auth.xml's google_auth_server_client_id from
    [google_auth] for the Android Kotlin bridge to read.
  - wire_native_lib_kotlin_sources is a general resolver: scans
    node_modules for perry.nativeLibrary.targets.android.kotlin_sources
    + gradle_dependencies and merges them into the Gradle project.
  - perry-ui-android's PerryActivity.onCreate reflection-calls
    PerryGoogleAuth.install(this) when the class is on the classpath
    (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a
glance_source field used to warn-and-skip ("Android Glance build path
not yet wired — follow-up issue #676 (Glance)."). Now wired:
build_declared_widgets_android in widget_build.rs mirrors the iOS
slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/,
emits res/xml/widget_info_<name>.xml, and injects a <receiver> block
into AndroidManifest.xml's <application>. Called from
build_and_run_android after the deeplinks injection + [google_auth]
Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014:
http::__get_statusMessage and http::__get_headers had no API_MANIFEST
counterpart for IncomingMessage. The test
every_dispatch_entry_has_manifest_counterpart was failing on every PR
opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two
missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes
4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device
sign-in + widget render not exercised in this session —
Ralph/downstream-GSC-Master will validate against real iOS device +
Android emulator next.

Closes #1138, closes #1139.
proggeramlug added a commit that referenced this pull request May 20, 2026
…uild path

#1138: extract @perryts/google-auth to standalone npm package + real SDK
integration. The v0.5.847 MVP shipped the binding as
crates/perry-ext-google-auth with all three FFI entry points resolving
"not-yet-implemented" on every platform — downstream (GSC Master)
couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit /
play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK
(iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin
bridge over androidx.credentials CredentialManager + GetGoogleIdOption
(Android, via JNI from crate-android using a new perry_android_jvm()
weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
  - removed crates/perry-ext-google-auth/, types/perry/google-auth/,
    test_google_auth_compile.ts, well_known_bindings.toml entry,
    native_table.rs NativeModSig rows, runtime_decls.rs declarations,
    api-manifest entries — the npm package's nativeLibrary.functions
    drives codegen ffi_signatures, same path as other @perryts/* deps.
  - inject_google_auth_info_plist writes GIDClientID / GIDServerClientID
    / GIDDefaultScopes from [google_auth] in perry.toml into the iOS
    Info.plist.
  - inject_google_auth_android_resources writes
    res/values/google_auth.xml's google_auth_server_client_id from
    [google_auth] for the Android Kotlin bridge to read.
  - wire_native_lib_kotlin_sources is a general resolver: scans
    node_modules for perry.nativeLibrary.targets.android.kotlin_sources
    + gradle_dependencies and merges them into the Gradle project.
  - perry-ui-android's PerryActivity.onCreate reflection-calls
    PerryGoogleAuth.install(this) when the class is on the classpath
    (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a
glance_source field used to warn-and-skip ("Android Glance build path
not yet wired — follow-up issue #676 (Glance)."). Now wired:
build_declared_widgets_android in widget_build.rs mirrors the iOS
slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/,
emits res/xml/widget_info_<name>.xml, and injects a <receiver> block
into AndroidManifest.xml's <application>. Called from
build_and_run_android after the deeplinks injection + [google_auth]
Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014:
http::__get_statusMessage and http::__get_headers had no API_MANIFEST
counterpart for IncomingMessage. The test
every_dispatch_entry_has_manifest_counterpart was failing on every PR
opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two
missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes
4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device
sign-in + widget render not exercised in this session —
Ralph/downstream-GSC-Master will validate against real iOS device +
Android emulator next.

Version bump + CHANGELOG entry intentionally omitted — Ralph applies
those at merge time (per CLAUDE.md "External contributor PRs" guidance,
avoiding the patch-version collisions that have hit this PR twice
already as main bumps in parallel).

Closes #1138, closes #1139.
proggeramlug added a commit that referenced this pull request May 20, 2026
…uild path

#1138: extract @perryts/google-auth to standalone npm package + real SDK integration. The v0.5.847 MVP shipped the binding as crates/perry-ext-google-auth with all three FFI entry points resolving "not-yet-implemented" on every platform — downstream (GSC Master) couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit / play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK (iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin bridge over androidx.credentials CredentialManager + GetGoogleIdOption (Android, via JNI from crate-android using a new perry_android_jvm() weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
- removed crates/perry-ext-google-auth/, types/perry/google-auth/, test_google_auth_compile.ts, well_known_bindings.toml entry, native_table.rs NativeModSig rows, runtime_decls.rs declarations, api-manifest entries — the npm package's nativeLibrary.functions drives codegen ffi_signatures, same path as other @perryts/* deps.
- inject_google_auth_info_plist writes GIDClientID / GIDServerClientID / GIDDefaultScopes from [google_auth] in perry.toml into the iOS Info.plist.
- inject_google_auth_android_resources writes res/values/google_auth.xml's google_auth_server_client_id from [google_auth] for the Android Kotlin bridge to read.
- wire_native_lib_kotlin_sources is a general resolver: scans node_modules for perry.nativeLibrary.targets.android.kotlin_sources + gradle_dependencies and merges them into the Gradle project.
- perry-ui-android's PerryActivity.onCreate reflection-calls PerryGoogleAuth.install(this) when the class is on the classpath (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a glance_source field used to warn-and-skip ("Android Glance build path not yet wired — follow-up issue #676 (Glance)."). Now wired: build_declared_widgets_android in widget_build.rs mirrors the iOS slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/, emits res/xml/widget_info_<name>.xml, and injects a <receiver> block into AndroidManifest.xml's <application>. Called from build_and_run_android after the deeplinks injection + [google_auth] Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014: http::__get_statusMessage and http::__get_headers had no API_MANIFEST counterpart for IncomingMessage. The test every_dispatch_entry_has_manifest_counterpart was failing on every PR opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes 4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device sign-in + widget render not exercised in this session — Ralph/downstream-GSC-Master will validate against real iOS device + Android emulator next.

Version bump + CHANGELOG entry intentionally omitted — Ralph applies those at merge time (per CLAUDE.md "External contributor PRs" guidance, avoiding the patch-version collisions that have hit this PR twice already as main bumps in parallel).

Closes #1138, closes #1139.
proggeramlug added a commit that referenced this pull request May 20, 2026
…uild path (#1165)

#1138: extract @perryts/google-auth to standalone npm package + real SDK integration. The v0.5.847 MVP shipped the binding as crates/perry-ext-google-auth with all three FFI entry points resolving "not-yet-implemented" on every platform — downstream (GSC Master) couldn't migrate off its perry-searchbird-google-auth fork.

Now extracted to PerryTS/google-auth (sibling to PerryTS/storekit / play-billing / etc.) with the real Swift bridge over GoogleSignIn SDK (iOS/macOS, opt-in via PERRY_GOOGLE_SIGN_IN_FRAMEWORK_DIR) and Kotlin bridge over androidx.credentials CredentialManager + GetGoogleIdOption (Android, via JNI from crate-android using a new perry_android_jvm() weak extern that perry-ui-android exports from JNI_OnLoad).

Perry-side wiring lives here:
- removed crates/perry-ext-google-auth/, types/perry/google-auth/, test_google_auth_compile.ts, well_known_bindings.toml entry, native_table.rs NativeModSig rows, runtime_decls.rs declarations, api-manifest entries — the npm package's nativeLibrary.functions drives codegen ffi_signatures, same path as other @perryts/* deps.
- inject_google_auth_info_plist writes GIDClientID / GIDServerClientID / GIDDefaultScopes from [google_auth] in perry.toml into the iOS Info.plist.
- inject_google_auth_android_resources writes res/values/google_auth.xml's google_auth_server_client_id from [google_auth] for the Android Kotlin bridge to read.
- wire_native_lib_kotlin_sources is a general resolver: scans node_modules for perry.nativeLibrary.targets.android.kotlin_sources + gradle_dependencies and merges them into the Gradle project.
- perry-ui-android's PerryActivity.onCreate reflection-calls PerryGoogleAuth.install(this) when the class is on the classpath (no-op otherwise).

#1139: Android Glance widget build path — [[widget]] entries with a glance_source field used to warn-and-skip ("Android Glance build path not yet wired — follow-up issue #676 (Glance)."). Now wired: build_declared_widgets_android in widget_build.rs mirrors the iOS slice — copies sources into app/src/main/java/<pkg>/widgets/<name>/, emits res/xml/widget_info_<name>.xml, and injects a <receiver> block into AndroidManifest.xml's <application>. Called from build_and_run_android after the deeplinks injection + [google_auth] Android resource write.

Also folds in 2 pre-existing manifest_consistency drifts from v0.5.1014: http::__get_statusMessage and http::__get_headers had no API_MANIFEST counterpart for IncomingMessage. The test every_dispatch_entry_has_manifest_counterpart was failing on every PR opened after v0.5.1014 (e.g. #1159's cargo-test failure); the two missing rows in entries.rs make the gate green.

Tests: 5 new widget_build unit tests + manifest_consistency now passes 4/4. cargo test -p perry widget_build green (9/9). End-to-end on-device sign-in + widget render not exercised in this session — Ralph/downstream-GSC-Master will validate against real iOS device + Android emulator next.

Version bump + CHANGELOG entry intentionally omitted — Ralph applies those at merge time (per CLAUDE.md "External contributor PRs" guidance, avoiding the patch-version collisions that have hit this PR twice already as main bumps in parallel).

Closes #1138, closes #1139.
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