商戶支持問題記錄

背景:

?這篇文章用來記錄一些商戶支持過程中遇到的問題和解決思路,也算是對(duì)自己工作的一個(gè)記錄吧。

1.module模塊嵌入問題( AndroidManifest.xml合并沖突)

? ? 在集成SDK時(shí),若SDK與主module(通常為app)的AndroidManifest.xml發(fā)生合并沖突,嘗試在主module的Manifest文件中配置tools屬性。



2.標(biāo)題欄遮擋問題

? ? 商戶APP在加載我們的webview頁面時(shí),由于APP做了沉浸式處理,導(dǎo)致手機(jī)導(dǎo)航欄圖標(biāo)(電池,運(yùn)營商標(biāo)識(shí)等)遮擋了webview頂部的操作按鈕,影響用戶操作。

解決方式:

在AndroidManifest.xml文件中對(duì)activity的聲明添加

android:theme="@android:style/Theme.Light.NoTitleBar"

? ? ? 隱藏主工程APP設(shè)置的titlebar效果,使用系統(tǒng)titlebar,這樣頁面可以自動(dòng)下移不遮擋了,后來我在對(duì)接支付寶的時(shí)候,發(fā)現(xiàn)阿里也在自己的H5頁面配置上有加這一句,應(yīng)該也是考慮到這個(gè)因素。


3.橋接方法不生效問題(混淆規(guī)則)

在targetSdkVersion 17以上需要添加接口JavaScriptInterface才能用,即在JS調(diào)用的Java代碼上方加上@JavaScriptInterface注解,同時(shí),在混淆代碼時(shí),注意不要混淆JavascriptInterface的注解,否則會(huì)出現(xiàn)js不能調(diào)用java代碼的情況。

-keepattributes *Annotation*

-keepattributes *JavaScriptInterface*


4.返回頁面問題(activity啟動(dòng)模式)

??喚起銀行APP支付成功后,在成功頁點(diǎn)擊“返回商戶”按鈕,喚起商戶內(nèi)嵌回調(diào)activity,商戶想直接收起該頁面,返回自己的訂單頁,但finish 回調(diào)activity后,回到了手機(jī)銀行。

我們假定商戶APP為A,銀行APP為B,由A喚起B(yǎng)時(shí),由任務(wù)棧S1跳轉(zhuǎn)到新任務(wù)棧S2執(zhí)行,點(diǎn)擊“返回商戶”,雖然回到了商戶APP,

此時(shí)task還在S2中執(zhí)行,所以執(zhí)行完上述邏輯后,只是關(guān)閉了當(dāng)前頁面,并沒有回到商戶APP。

為什么還在S2執(zhí)行呢?理論上不同的activity應(yīng)該在不同的任務(wù)中執(zhí)行,但android在設(shè)計(jì)時(shí),考慮到無縫的用戶體驗(yàn),在喚起時(shí),會(huì)將不同的activity保存在相同的任務(wù)中,這樣看起來像是在一個(gè)應(yīng)用中執(zhí)行。

解決方案:

1. intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent添加喚起方式配置

2. 修改回調(diào)activity的啟動(dòng)類型,由singleTop改為singleTask。

<activity

android:name=".icbcPay.PayResultHandler"

android:exported="true"

android:launchMode="singleTask">

</activity>

這兩種方式是一樣的,以singleTask方式啟動(dòng)后,系統(tǒng)會(huì)嘗試尋找與目標(biāo)activity相關(guān)聯(lián)的任務(wù),并嘗試在該任務(wù)中啟動(dòng)。


微信支付的回調(diào)activity配置的是“singleTop”,猜測(cè)是intent啟動(dòng)的時(shí)候做了配置,不然感覺也會(huì)出這種問題。

關(guān)于activity的啟動(dòng)模式(任務(wù)和返回棧

? ?(1)standard 默認(rèn)啟動(dòng)模式,不管有沒有已經(jīng)存在的實(shí)例,都會(huì)生成新的實(shí)例

? ?(2)singleTop 跳轉(zhuǎn)時(shí)系統(tǒng)會(huì)現(xiàn)在棧結(jié)構(gòu)中尋找是否有一個(gè)activity實(shí)例位于棧頂,如果有,則不再生成新的實(shí)例。如果沒有,或者有但不在棧頂,則生成新的實(shí)例。

? ?(3)singleTask 啟動(dòng)新任務(wù)執(zhí)行,在啟動(dòng)activity時(shí),若有一個(gè)運(yùn)行著這個(gè)activity的task,那這個(gè)activity實(shí)例會(huì)被調(diào)到前臺(tái),處于該activity之上的其他頁面會(huì)被清掉。

? ? ? (4) singleInstance?開辟一個(gè)只允許一個(gè)activity實(shí)例在里面運(yùn)行的task. 如果用同樣的intent再次啟動(dòng)這個(gè)activity,task會(huì)被調(diào)到前臺(tái),其Activity.onNewIntent()?會(huì)被調(diào)用. 如果這個(gè)activity實(shí)例要啟動(dòng)一個(gè)新activity,那么這個(gè)新activity會(huì)在一個(gè)新task中運(yùn)行.

? ? ? ?singleTop適合接收通知啟動(dòng)的內(nèi)容顯示頁面。例如,某個(gè)新聞客戶端的新聞內(nèi)容頁面,如果收到10個(gè)新聞推送,每次都打開一個(gè)新聞內(nèi)容頁面是很煩人的。

? ? ? ? singleTask適合作為程序入口點(diǎn)。例如瀏覽器的主界面。不管從多少個(gè)應(yīng)用啟動(dòng)瀏覽器,只會(huì)啟動(dòng)主界面一次,其余情況都會(huì)走onNewIntent,并且會(huì)清空主界面上面的其他頁面。之前打開過的頁面,打開之前的頁面就ok,不再新建。

? ? ? ? ?singleInstance適合需要與程序分離開的頁面。例如鬧鈴提醒,將鬧鈴提醒與鬧鈴設(shè)置分離。singleInstance不要用于中間頁面,如果用于中間頁面,跳轉(zhuǎn)會(huì)有問題,比如:A -> B (singleInstance) -> C,完全退出后,在此啟動(dòng),首先打開的是B。

? ? ? ?當(dāng)ActivityA的LaunchMode為SingleTop時(shí),如果ActivityA在棧頂,且現(xiàn)在要再啟動(dòng)ActivityA,這時(shí)會(huì)調(diào)用onNewIntent()方法?

? ? ? 當(dāng)ActivityA的LaunchMode為SingleInstance,SingleTask時(shí),如果已經(jīng)ActivityA已經(jīng)在堆棧中,那么此時(shí)會(huì)調(diào)用onNewIntent()方法?

? ? ? ?當(dāng)ActivityA的LaunchMode為Standard時(shí),由于每次啟動(dòng)ActivityA都是啟動(dòng)新的實(shí)例,和原來啟動(dòng)的沒關(guān)系,所以不會(huì)調(diào)用原來ActivityA的onNewIntent方法


5.回調(diào)路徑找不到(app packageName與applicationId的關(guān)系)

? ? ?SDK回調(diào)路徑由app的packageName+固定名稱activity組成,通常我們?cè)诠こ汤?,如果在build.gradle里指定applicationId,那么getPackageName獲得的是applicationId,否則才是AndroidManifest.xml 配置的 packageName,AndroidManifest.xml里配置的packageName與工程路徑一致。applicationId可以視為應(yīng)用的唯一標(biāo)識(shí)符,運(yùn)行ID,上架之后不能再改變。

? ? ?假設(shè)我們?cè)贏ndroidManifest.xml里配置的是path1,applicationId是path2,那么通過getPackageName()獲得的是path2,回調(diào)路徑是path2+activity name,而這個(gè)路徑,在工程下是找不到的。

? ? 這個(gè)問題最后沒有想到合適的方法的解決,當(dāng)時(shí)是客戶硬在工程路徑下,創(chuàng)建了path2+activity文件解決的,微信也是通過packageName+activity來做回調(diào)的,有環(huán)境了試試會(huì)不會(huì)有問題。如果沒問題,他們是怎么拿到正確的工程路徑呢……

2018.6.6

?這個(gè)問題我今天想起來了。。。用activity-alias 控制目標(biāo)跳轉(zhuǎn)路徑可以實(shí)現(xiàn),在主工程AndroidManifest.xml中,聲明path2+activity,配置activity-alias,path1的targetActivity指向path2.

2018.6.13

其實(shí)還是要新建path2+activity文件,這個(gè)方法行不通

6.Toast導(dǎo)致的閃退問題

出現(xiàn)“訂單數(shù)據(jù)不完整”這種場(chǎng)景時(shí),SDK引起了宿主APP的crash。

原因是該Toast在AsyncTask的doInBackground中顯示,這段代碼執(zhí)行在非主線程中且未初始化Looper。

Toast一定要運(yùn)行在主線程(UI線程)嗎?

? ? ? 其實(shí)不是的,看了Toast的源碼后,其實(shí)Toast也是利用了進(jìn)程間通訊,其構(gòu)造函數(shù)里需傳入looper。而Activity和service之所以不需要初始化looper,是因?yàn)橹骶€程(ActivityThread)初始化了looper。

private void showMessage(final Context context, final String msg){

new Thread(){

public void run(){

Looper.prepare();

Toast.makeText(context,msg,Toast.LENGTH_SHORT).show();

Looper.loop();

}}.start();

}

Looper會(huì)一直死循環(huán),占用內(nèi)存,該線程不會(huì)被釋放,新起線程執(zhí)行,建議還是用Handler的方式去實(shí)現(xiàn)。

? ? ? ? Handler?handler?=?new?Handler(Looper.getMainLooper());??????????

? ? ? ? handler.post(new?Runnable()?{??????????????

? ? ? ?@Override??????????????

? ? ? ? public?void?run()?{?????????????????

? ? ? ? ?Toast?toast?=?Toast.makeText(context,?text,?duration);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?toast.show();??????????????}??????????});??

UI操作一定要在UI線程里執(zhí)行嗎?

Toast可能是一個(gè)特例,其實(shí)UI操作不一定要在UI線程里執(zhí)行。之所以子線程不能更新界面,是因?yàn)锳ndroid在線程的方法里面采用checkThread進(jìn)行判斷是否是主線程,而這個(gè)方法是在ViewRootImpl中的,這個(gè)類是在onResume里面才生成的,因此,如果這個(gè)時(shí)候子線程在onCreate里面生成更新UI,而且沒有做阻塞,就是耗時(shí)多的操作,還是可以更新UI的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容