首先附上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层扩展插件类的对应关系
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
获取可以使用下面的的方法。直接放到插件类中即可。
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;
}