The injected bridge sends share with no callbackId and returns nothing:
// packages/ios/templates/CraftApp.swift:2010
share: function(text) {
window.webkit.messageHandlers.craft.postMessage({action: 'share', text: text});
},// packages/android/templates/CraftBridge.kt.template
share: function(text, title) {
CraftAndroid.share(text, title || '');
},The iOS native side, meanwhile, is written as though a promise were waiting
(CraftApp.swift:666-677):
case "share":
if config.enableShare {
if let options = body["options"] as? [String: Any] {
share(options: options, callbackId: callbackId)
} else if let text = body["text"] as? String {
share(options: ["text": text], callbackId: callbackId)
} else {
rejectCallback(callbackId, error: "Nothing to share", code: "INVALID_ARGUMENT")
}
} else {
rejectCallback(callbackId, error: "Sharing is disabled", code: "CAPABILITY_DISABLED")
}callbackId is always nil here, and both resolveCallback and
rejectCallback open with guard let id = callbackId else { return }. So all
four outcomes — shared, cancelled, nothing-to-share, capability-disabled — are
silently discarded.
The visible consequence is that window.craft.share('x') in an app with
enableShare: false does nothing at all and reports nothing. Observed on a
simulator while building #199: the call appeared to succeed because it returned
undefined, which Promise.resolve turns into a resolved promise.
Every other capability-gated action on this surface returns a promise and
rejects with CAPABILITY_DISABLED; share is the odd one out. Making it
return a promise and pass a callbackId would need no change to the Swift
side, which is already written for it.
Not covered by the mobile E2E suite for the same reason it is a bug: there is nothing to assert on.