Skip to content

Add bridgeable UIApplication.shouldShowPermissionRationale(_:) - #498

Open
vincentborko wants to merge 1 commit into
skiptools:mainfrom
vincentborko:pr/permission-rationale
Open

Add bridgeable UIApplication.shouldShowPermissionRationale(_:)#498
vincentborko wants to merge 1 commit into
skiptools:mainfrom
vincentborko:pr/permission-rationale

Conversation

@vincentborko

Copy link
Copy Markdown
Contributor

Add a bridged UIApplication.shouldShowPermissionRationale(_:)

Motivation

UIApplication.requestPermission(_:showRationale:) already consults
ActivityCompat.shouldShowRequestPermissionRationale, but that overload cannot be
bridged — as noted in the source today:

// SKIP @bridge
public func requestPermission(_ permission: String) async -> Bool {
    // We can't bridge the `showRationale` parameter async closure
    return await requestPermission(permission, showRationale: nil)
}

So a natively-compiled SkipFuse app has no way to ask whether the next permission
request will actually put a dialog on screen. Android offers no readable
"undetermined" state — checkSelfPermission returns DENIED both for "never asked"
and for "declined" — so reconstructing that distinction requires the rationale bit,
and today the only route is hand-rolled JNI reflection into the Activity.

Change

A closure-free, bridgeable accessor next to the existing request methods:

// SKIP @bridge
public func shouldShowPermissionRationale(_ permission: String) -> Bool {
    guard let activity = self.androidActivity else { return false }
    return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)
}

It returns false both for "never requested" and for "permanently denied"; the doc
comment says so, since callers that need to separate those must combine it with their
own record of having asked. That mirrors the semantics Android itself exposes rather
than inventing a richer state.

Bridging decision

A plain String -> Bool method, so it crosses the bridge unchanged. Deliberately not
an overload of the existing requestPermission family: the useful call happens
before a request, and the existing showRationale callback fires during one and
only when a rationale is warranted, which cannot express the pre-request question.

Testing

  • swift test green — 92 tests, 0 failures, native XCTest plus the transpiled Kotlin
    suite under JUnit in the same run.

  • Verified the new API reaches the generated Kotlin as
    open fun shouldShowPermissionRationale(permission: String): Boolean.

  • Verified the @bridge annotation produces the expected entry in the generated
    UIApplication_Bridge.swift of a consuming natively-compiled SkipFuse app:

    public func shouldShowPermissionRationale(_ p_0: String) -> Bool {  }
    // getMethodID(name: "shouldShowPermissionRationale", sig: "(Ljava/lang/String;)Z")

    That app's Gradle assembleDebug is green against it.

Note that the bridged call goes through JNI like the rest of the bridge, so callers
still need to be on the main actor; this removes the need for hand-rolled reflection,
not the isolation requirement.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant