1. 程式人生 > >Android平臺以WebView方式整合H5+SDK和支付寶登入授權外掛開發思路總結

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的詳細方法與支付一樣,請參考支付的接入配置流程

iOS整合流程詳解Android整合流程詳解,我們點選Android整合流程詳解連結,進入android整合講解,按照步驟配置並且下載官方demo,有圖有真相。

接入完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;
}