Android平臺以WebView方式整合H5+SDK和支付寶登入授權外掛開發思路總結
首先附上Demo地址,大家可以去GitHub上面下載https://github.com/GitLGH/AlipayDemo
一:思路總結
螞蟻金融開發平臺上面對於支付寶登入授權部分使用的原生android方式進行配置的,而當前專案採用Hbuilder mui的方式,mui框架沒有整合支付寶登入授權功能,這就需要我們使用H5+sdk的第二個用途,即通過原生程式碼擴充套件HTML5+ runtime的功能。
第一步: 那麼首先第一步就是要把現有的Hbuilder專案整合到android的原生工程當中,這時候需要我們仔細閱讀Dcloud的官方文件(關於H5+sdk的部分),官方文件寫的實在是太草率了,對於我這種java後臺開發人員來說就是看不懂啊,堅持看了三遍才把整篇文章看完,(說實話,看了三遍還是不是很明白),不過幸運的是我在官方文件中找到了這樣的一個位置,有圖有真相。
(http://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/13232)使用新版 本5+SDK建立最簡Android原生工程
按照這個步驟建立完之後,現有的Hbuilder專案就成功整合到原生android中了,在建立期間會需要sdk的包,需要在http://ask.dcloud.net.cn/article/103位置將最新的sdk下載下來。(這個裡面不但包含最新的sdk還包含官方的demo)。
第二步:那就是思考如何將支付寶登入授權整合進來了,首先我到螞蟻金服開發者平臺申請了App支付寶登入功能(需要簽約),點選App支付寶登入功能進入之後(也可以直接訪問https://docs.open.alipay.com/218/105326/),在快速接入的第三步整合並配置sdk中,講解了如何整合客戶端sdk,官方文件提到,無線賬戶授權與App支付共用同一個SDK,整合SDK的詳細方法與支付一樣,請參考支付的接入配置流程
接入完sdk之後我們回到app支付寶登入的解說文件中,有圖有真相。
但是很坑的是這裡只是說了呼叫String authV2(String info)方法,根本沒說在哪裡呼叫,怎麼呼叫,幸好我們下載了官方的demo,於是我開始研究官方的demo,首先將demo引入到android studio中,將其執行起來,走一下步驟,然後去看demo的原始碼,在demo的PayDemoActivity的類中,我們找到了支付寶賬戶授權業務示例,有圖有真相。
這時候又出現了一個問題,那就是我的Hbuilder專案的的支付寶登入的按鈕,在js裡面如何呼叫原生android裡面的java程式碼那? 於是我又回到了Dcloud的官方文件的H5+sdk的部分,看到裡面有一個H5+外掛開發,裡面說到了js和原生程式碼之間的互動,有圖有真相。
於是仔細讀了官方文件,真心還是看不太懂啊,官方給了具體的事例程式碼,但是根本沒說具體的呼叫過程,沒辦法只能看看在第一步下載的最新sdk的那個包,裡面有外掛開發的demo,然後又在網上查一檢視看有沒有那個大神做過這種外掛開發,果真讓我查到了,在這個https://www.jianshu.com/p/e14cd2c26ec0網址裡面,有一位大神做了總結,結合網上的總結和官方的demo例子,終於有了思路,於是開始按照官方的方式開始配置,以下總結一下配置過程:1、建立擴充套件外掛JS API(這裡使用非同步形式)
document.addEventListener( "plusready", function()
{
var _BARCODE = 'Alipay',---data目錄下properties裡面配置的名字
B = window.plus.bridge;
var ALipayPlugin =
{
/*//同步
alipayLogin : function (Argus)
{
return B.execSync(_BARCODE, "alipayLogin", [Argus]);
}*/
//非同步
alipayLogin : function (Argus1, successCallback, errorCallback )
{
var success = typeof successCallback !== 'function' ? null : function(args)
{
successCallback(args);
},
fail = typeof errorCallback !== 'function' ? null : function(code)
{
errorCallback(code);
};
callbackID = B.callbackId(success, fail);
return B.exec(_BARCODE, "alipayLogin(方法名)", [callbackID, Argus1]);
}
};
window.plus.Alipay = ALipayPlugin
}, true );
2、在Android工程的assets\data\properties.xml檔案中宣告外掛類別名和Native層擴充套件外掛類的對應關係
<feature name="Alipay" value="com.example.H5PlusPlugin.AlipayFeature"></feature>
3、編寫外掛類
public class AlipayFeature extends StandardFeature {
public void alipayLogin(IWebview iWebview, JSONArray jsonArray) {
String url=null;
JSONObject retJSONObj=null;
try {
url = jsonArray.getString(1);
Log.e("badge", "url=" + url);
// Toast.makeText(iWebview.getContext(), "url=" + url, Toast.LENGTH_SHORT).show();
//呼叫支付寶的官方demo裡面的登入授權方法
//非同步方式JSUtil.execCallback(pWebview, CallBackID, newArray, JSUtil.OK, false);返回到js的呼叫部分
} catch (JSONException e) {
e.printStackTrace();
}
}
}
4、js實現呼叫外掛,前提需要在mainfest.json檔案中加入配置外掛名稱(也就是分配許可權)
呼叫
mui.plusReady(function () {
document.getElementById('Alipay').addEventListener('tap', function() {
plus.Alipay.alipayLogin(‘傳入外掛資料’, function( result ) {
//成功之後非同步帶回來的資料加入判斷
if(result!=null&&result!=''){
alipay(result);//授權之後的處理函式—自定義的
}
},function(result){//失敗情況的函式
window.location.href ="error.html";
});
})}
注意:支付寶官方demo呼叫authV2是通過AuthTask物件,這個物件建立時需要activity物件,在支付寶demo中activity是原生android傳入的,而外掛開發這裡是通過js到達原生外掛部分的,所以activity需要手動獲取。
AuthTask authTask = new AuthTask(activity);
// 呼叫授權介面,獲取授權結果
Log.e("authV2","456");
Map<String, String> result = authTask.authV2(url, true);
獲取可以使用下面的的方法。直接放到外掛類中即可。
public Activity getActivity() {
Class activityThreadClass = null;
try {
activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map activities = (Map) activitiesField.get(activityThread);
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}