Add handleSignInLink for Android (feature parity with iOS)#73
Merged
Conversation
`handleSignInLink` is implemented on iOS and called from the JS bridge (`GlobalContext.tsx`) for deep link sign-in, but has no Android implementation. This means deep link sign-in silently fails on Android. Adds `@ReactMethod handleSignInLink(url)` to `RowndPluginModule.kt`. Uses reflection to call the internal `SignInLinkApi` since the Android SDK doesn't expose a public equivalent of iOS's `Rownd.handleSmartLink`.
Reviewer's GuideImplements Android parity for deep link sign-in by adding a new handleSignInLink React Native bridge method that delegates to the internal Rownd SignInLinkApi via reflection and sets up an ACTION_VIEW intent on the current activity. Sequence diagram for Android deep link sign-in handling via handleSignInLinksequenceDiagram
actor User
participant AndroidOS
participant ReactNativeJS as ReactNative_JS_GlobalContext
participant RowndPluginModule
participant Rownd
participant SignInLinkApi
User->>AndroidOS: Tap deep link URL
AndroidOS->>ReactNativeJS: Launch app with deep link intent
ReactNativeJS->>RowndPluginModule: handleSignInLink(url)
RowndPluginModule->>RowndPluginModule: Get currentActivity
alt Activity available
RowndPluginModule->>RowndPluginModule: Set activity.intent = ACTION_VIEW(url)
RowndPluginModule->>Rownd: getSignInLinkApi_android_release()
Rownd-->>RowndPluginModule: SignInLinkApi instance
RowndPluginModule->>SignInLinkApi: signInWithLinkIfPresentOnIntentOrClipboard_android_release(activity)
SignInLinkApi-->>RowndPluginModule: Sign-in result
RowndPluginModule-->>ReactNativeJS: Resolve sign-in flow (success/failure)
else No activity
RowndPluginModule-->>ReactNativeJS: Return early (no-op)
end
Class diagram for RowndPluginModule with new handleSignInLink methodclassDiagram
class RowndPluginModule {
+RowndPluginModule(reactContext: ReactApplicationContext)
+handleSignInLink(url: String) void
+requestSignIn(signInConfig: ReadableMap) void
}
class Rownd {
+getSignInLinkApi_android_release() SignInLinkApi
}
class SignInLinkApi {
+signInWithLinkIfPresentOnIntentOrClipboard_android_release(activity: android.app.Activity) void
}
class ReactNativeJS_GlobalContext {
+handleSignInLink(url: string) void
}
ReactNativeJS_GlobalContext --> RowndPluginModule : calls
RowndPluginModule ..> Rownd : reflection getSignInLinkApi_android_release
Rownd --> SignInLinkApi : returns instance
RowndPluginModule ..> SignInLinkApi : reflection signInWithLinkIfPresentOnIntentOrClipboard_android_release
RowndPluginModule --> android.app.Activity : sets ACTION_VIEW intent
class android.app.Activity
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- Overwriting
activity.intentwith a newACTION_VIEWintent could interfere with other logic that relies on the original launch intent; consider passing a localIntentinstance directly to the reflective call instead of mutatingactivity.intent. - The reflective calls rely on hard-coded, release-specific method names (e.g.,
getSignInLinkApi$android-release); if possible, centralize these strings as constants or add a small helper/wrapper to reduce the risk of typos and ease future refactors. - The
catch (Exception)block only logs the error message; consider logging the full exception or at least the stack trace to aid debugging when the reflection fails on certain builds or devices.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Overwriting `activity.intent` with a new `ACTION_VIEW` intent could interfere with other logic that relies on the original launch intent; consider passing a local `Intent` instance directly to the reflective call instead of mutating `activity.intent`.
- The reflective calls rely on hard-coded, release-specific method names (e.g., `getSignInLinkApi$android-release`); if possible, centralize these strings as constants or add a small helper/wrapper to reduce the risk of typos and ease future refactors.
- The `catch (Exception)` block only logs the error message; consider logging the full exception or at least the stack trace to aid debugging when the reflection fails on certain builds or devices.
## Individual Comments
### Comment 1
<location path="android/src/main/java/com/reactnativerowndplugin/RowndPluginModule.kt" line_range="124-127" />
<code_context>
+ @ReactMethod
+ fun handleSignInLink(url: String) {
+ val activity = reactApplicationContext.currentActivity ?: return
+ activity.intent = android.content.Intent(
+ android.content.Intent.ACTION_VIEW,
+ android.net.Uri.parse(url)
+ )
+ try {
+ val apiGetter = Rownd.javaClass.getMethod("getSignInLinkApi\$android-release")
</code_context>
<issue_to_address>
**issue (bug_risk):** Assigning a new Intent to `activity.intent` may have unintended side effects on the host Activity.
This can break future `activity.intent` usage (e.g., subsequent reads, deep links, or lifecycle logic relying on the original intent). Instead, create a local `Intent` for the SDK call or mutate only the necessary fields on the existing `activity.intent` so the Activity’s state isn’t globally changed.
</issue_to_address>
### Comment 2
<location path="android/src/main/java/com/reactnativerowndplugin/RowndPluginModule.kt" line_range="136-138" />
<code_context>
+ android.app.Activity::class.java
+ )
+ method.invoke(api, activity)
+ } catch (e: Exception) {
+ Log.e("RowndPlugin", "handleSignInLink failed: ${e.message}")
+ }
+ }
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Catching `Exception` and only logging the message hides useful debugging information and may swallow important failures.
This turns any reflection, parsing, or SDK failure into a single log line and drops the stack trace. Please log the full exception (e.g., `Log.e(
```suggestion
} catch (e: Exception) {
Log.e("RowndPlugin", "handleSignInLink failed", e)
}
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Preserve stack trace by passing exception object to Log.e() instead of only logging the message string. This improves debugging for reflection, parsing, or SDK failures.
Contributor
Author
|
mhamann
approved these changes
Feb 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
handleSignInLinkis implemented on iOS and called from the JS bridge (GlobalContext.tsx) for deep link sign-in, but has no Android implementation. This means deep link sign-in silently fails on Android.Adds
@ReactMethod handleSignInLink(url)toRowndPluginModule.kt. Uses reflection to call the internalSignInLinkApisince the Android SDK doesn't expose a public equivalent of iOS'sRownd.handleSmartLink.Summary by Sourcery
New Features: