App-Callback-Mark
App 之间回调是常有的事, 特别是一些提供第三方登录/第三方支付的 App, 更是需要提供调起, 登录/支付, 回调原 App 的功能. 在实现的过程中遇到一些问题, 所以记录一下.
接下来调起界面称为 CallActivity, 调起 App 称为 Call App , 被调起页面称为 PayActivity. 被调起 App 称为 Pay App.
常见方案: startActivityForResult
最常见的当然是 通过 startActivityForResult() 使用隐式 Intent 调起, 然后在 onActivityResult() 中捕捉回调并处理成功失败逻辑了. 这种方法大部分人都会, 说点遇到的问题吧:
问题来了
- 问题一:
- 打开
Pay Activity后可以切到后台, 再切回来, 这样做一方面安全性不够, 另一方面不符合支付工具的特性. 第三方应用调起支付应用后, 对用户的感觉不应该是完整的打开了一个应用, 而应该是仅仅启动了支付的一个功能, 切到后台后应该无法再切回该支付页面, 最近打开的应用页面也不该展示 Pay App. - 在
AndroidManifest.xml中加上android:excludeFromRecents="true"
- 打开
- 问题二:
- 支付成功后, 按 Home 键切到后台, 再切回
Call App, 这时候没有触发onActivityResult() - 这是系统问题, 正常逻辑, 只能在
onResume()里面查询后台是否成功.
- 支付成功后, 按 Home 键切到后台, 再切回
- 问题三:
- 如果已经打开了
Pay App, 然后切到后台, 打开到Call App, 调起Pay Activity后按返回键, 返回到Pay App的界面了. - 需要指定
PayActivity的 luanchMode 为singleInstance
- 如果已经打开了
- 问题一:
大坑来了
坑就在于这个
singleInstance, 在 Android 5.0 上一切正常, 但是在 Android 4.4 及以下版本,Call Activity调用startActivityForResult()后, 直接回调了onActivityResult(), 然后才打开Pay Activity.为此我记录了一下不同 luanchMode 对 Android 4.4 及以下版本回调的影响.
正常回调 -> Y
直接回调 -> N
| Call Activity | Standard | SingleTop | SingleTask | SingleInstance :---: | :---: | :---: | :---: | :---: | :---: Pay Activity | Standard | | Y | Y | Y | N SingleTop | | Y | Y | Y | N SingleTask | | N | N | N | N SingleInstance | | N | N | N | NstartActivityForResult 方案不可行
对于
startActivityForResult()来说, 想实现对 singleInstance 的回调是不可能了, 同时还有问题二也需要优化, 所以最好还是换个方案来执行.
透明中间页 + 广播方案
之前版本由于已经发布, 需要兼容旧版本, 同时为了优化问题二, 考虑在接入 sdk 中提供一个中间页面 Entry Activity. 另外对于 singleInstance 的问题, 考虑用广播来替代.
Call Activity -> Entry Activity -> Pay Activity
各页面功能如下:
Call Activity依旧执行 startActivityForResult 方法, sdk 内部直接调起
Pay Activity改为调起透明Entry Activity.在 onActivityResult 中处理回调逻辑.
Entry Activity设置 theme 为透明, 同时取消进入和退出的动画. 设置 luanchMode 为 singleTop
注册广播, 监听
Pay Activity发来的支付成功的广播直接通过
startActivity调起PayActivity在第二次进入
onResume()时判断是否收到了支付成功的广播, 否则当做支付失败处理.成功及支付都通过
setResult()的方式回调Pay Activity支付成功使用广播通知.