Android ACTION_SEND 分享到 X 成功后为何仍返回 RESULT_CANCELED?
结论
处理 ACTION_SEND 的应用没有义务在分享成功后调用 setResult(RESULT_OK)。Android 也没有提供标准 API,让发送应用判断目标应用是否通过通用分享完成了发帖。
在所述 X 版本中,成功发布和取消编辑都会返回 RESULT_CANCELED,发送应用无法仅凭这个结果区分两种情况。业务状态应记为“发布结果未知”,不能直接判定为“用户取消”。
chooser 回调可以确认用户选择了 X,无法确认帖子是否已发布。如果 X 没有提供额外的结果协议,当前流程能获得的就是这个目标选择信号。
为什么发布成功后仍会返回 RESULT_CANCELED?
ACTION_SEND 没有规定发布结果契约
Android 的 ACTION_SEND 文档写明 Output: nothing。它定义了如何把文本、图片等数据交给另一个应用,没有要求接收应用返回“发送成功”或“用户取消”。
接收应用可以通过 setResult() 返回结果,发送应用则需要按双方约定解释结果。使用 ActivityResultContracts.StartActivityForResult() 并不会为 ACTION_SEND 增加这样的约定。
RESULT_CANCELED 也可能表示没有返回结果
Activity 的默认结果是 RESULT_CANCELED。官方文档说明,目标 Activity 显式返回该值、没有返回任何结果,或者运行时崩溃,都可能让调用方收到 RESULT_CANCELED。因此,单凭这个结果码无法证明用户点击了取消。Activity 结果说明
目标应用可能已经完成发布,只是在退出时没有设置其他结果码。内部 Activity 的跳转和结果传递方式也可能影响调用方收到的结果。现有日志不足以确定 X 内部走了哪条路径。
data=null 只说明没有附带结果数据,也无法据此判断是否发布成功。
chooser 回调能确认什么?
Intent.createChooser() 的 IntentSender 回调报告用户选择了哪个处理组件。如果 EXTRA_CHOSEN_COMPONENT 中出现:
com.twitter.android/com.x.android.lib.ComposerActivity
就能确认用户选择了该组件。这个回调不会等待 X 完成发帖,也不会获取 X 服务端的发布状态。官方文档还提醒,用户放弃 chooser 或切换任务等情况下,回调可能不会到达,应用不能假定每次都能收到。目标选择回调说明
API 35 新增的 ChooserResult 和 EXTRA_CHOOSER_RESULT 扩展了 Sharesheet 的结果信息,可以描述选择目标、复制、编辑等操作,但仍不提供目标应用内部的发帖结果。Sharesheet 结果回调说明
发送应用应如何处理?
- 在 chooser 广播回调中记录“用户选择了分享目标”。
- 保存 Activity 返回结果,用于诊断,不根据它直接显示“发布成功”或“发布失败”。
- 如果业务必须确认发布,需要使用接收应用明确支持的回调协议,或者另行接入能够返回发布结果的平台接口。
现有分享 Intent 和 chooser 的创建方式可以保留,结果处理部分可改为:
val broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val component = if (
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
) {
intent?.getParcelableExtra(
Intent.EXTRA_CHOSEN_COMPONENT,
ComponentName::class.java
)
} else {
@Suppress("DEPRECATION")
intent?.getParcelableExtra<ComponentName>(
Intent.EXTRA_CHOSEN_COMPONENT
)
}
component?.let {
Log.d(
"ShareResult",
"targetSelected=${it.flattenToString()}"
)
// 只记录选择目标,不更新为“发布成功”。
}
}
}
val launcher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
Log.d(
"ShareResult",
"activityResultCode=${result.resultCode}, data=${result.data}"
)
// ACTION_SEND 没有统一的发布结果契约。
// 此处保留诊断日志,发布状态仍为未知。
}
广播注册和 PendingIntent 的创建沿用原有逻辑。目标选择事件应直接在 onReceive() 中处理,不必等 Activity 结果回调后再读取共享变量,也不要依赖两个回调的先后顺序。
如果不需要 Activity 返回的诊断信息,可以直接使用:
startActivity(
Intent.createChooser(
shareIntent,
null,
pendingIntent.intentSender
)
)
这样仍能接收目标选择回调,但更换启动方式无法帮助应用判断发布结果。
X 的 Activity 迁移是否导致了问题?
在给出的环境中,分享入口从:
com.twitter.composer.ComposerActivity
变为:
com.x.android.lib.ComposerActivity
这一变化可以作为向 X 报告问题时的复现线索,但不足以证明结果码变化由迁移导致,也无法据此判断这是有意调整还是回归问题。
即使旧版本在成功发布后曾返回 RESULT_OK,也只能说明那些版本采用了这种实现。除非 X 明确承诺了结果协议,否则发送应用不能将其视为稳定的接口契约。
业务需要确认发布结果时,应先核实平台是否提供适用的官方接口或回调,再按其授权要求和结果语义接入。另行调用发布接口属于另一套发布流程,不能自动确认用户在 X 编辑界面中的操作结果。
界面提示和统计可以记录“已选择 X”,发布状态仍应保留为“未知”。onResume()、页面停留时间以及是否读取了图片,都不足以证明帖子已经发布。
备注:内容仅供参考。
