Unity Android平台接入支付宝
额,最近折腾在unity项目中接入支付宝,记录下流程。
先来个官方文档:https://docs.open.alipay.com/204/106079/
配置
创建应用,配置应用参考上面的给的官网文档。
支付宝SDK
链接 https://doc.open.alipay.com/doc2/detail.htm?treeId=54&articleId=104509&docType=1
下载SDK&Demo。解压之后会有两个文件夹:alipay_demo和alipay_sdk,别急后面会用到。
创建android库工程
这里用AndroidStudio来创建Android工程,不用Eclipse了,配环境好蛋疼。。。
1.
创建一个新的Android工程,Package Name要和Unity -> PlayerSettings里的Bundle Identifier保持一致。
2.
Minimum API Level就直接默认得了,大部分通用
3.
选择Activity的模版,我们选择Empty Activity。因为不需要编写Android原生界面。
4.
然后是设置Activity的名字界面,因为我们不需要编程Android界面,所以取消勾选Generate Layout File选项。不取消也可以,可以创建工程后手动删除Layout文件夹。
5.
创建工作完成,下面对照着下图删除没用东西。
只保留了两个文件—— AndroidManifest.xml和MainActivity
6.
修改AndroidManifest,修改后如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xxl.youxigame">
<application
android:allowBackup="true"
android:supportsRtl="true">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
</activity>
</application>
</manifest>
7.
打开Gradle Scripts(Gradle是一种安卓构建脚本)下的build.gradle(Moudle:app),修改如下(这是因为库文件不能设置applcation Id,另外build.gradle会包含单元测试的配置,也需要删除):
//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
基本环境配置完毕,接下来就是接入支付宝SDK了。
接入支付宝
首先我们需要引入支付宝SDK的jar包,将alipay_sdk下的alipaySdk-20XXXXXX.jar和Unity提供的jar包拷贝到项目路径/app/libs文件夹下,
Unity提供的jar包路径是:
Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\classes.jar
如果你的项目采用il2cpp编译,那么路径则是:
Editor\Data\PlaybackEngines\AndroidPlayer\Variations\il2cpp\Release\Classes\classes.jar
然后回到AndroidStudio,菜单栏选择File -> Project Structure界面,点击app -> Dependencies如所示:
点击旁边的减号,删掉目前这三个以来库,然后点击加号 -> Jar Dependency,选择刚才拷贝到Libs下面的那两个jar文件,点击确定。可以发现build.gradle(Moudle:app)下depedencies里出现了支付宝的Sdk jar包,完整的build.gradle如下:
//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile files('libs/alipaySdk-20170710.jar')
compile files('libs/classes.jar')
}
到这里后,我们先来测试一下配置是否正确,再进行下面的步骤。
点击Android Studio左下角的Build Variants,如图:
将debug修改为release:
最后点击菜单栏Build -> Build APK,稍等,如果出现Build Successfully的提示,说明一切正常。如图:
点击Show in Explorer,选择outputs -> aar,会发现一个app-release.aar。这就是build生成的文件,aar可以视为jar的升级版。其实它们都只是一个zip文件。
注意:
生成的aar文件里,我们需要删除libs/class.jar!将aar文件后缀改为zip,使用压缩软件删除即可。因为Unity在打包时,会将自带的那个classes.jar拷贝进apk,如果aar里的classes.jar不删除,打包时就会产出冲突,得到下面的错误:
IOException: Failed to Move File / Directory from 'Temp/StagingArea\android-libraries\app-release\classes.jar' to 'Temp/StagingArea\android-libraries\app-release\libs\classes.jar'.
也就是说,每次我们测试后,都需要将aar里的这个jar包手动删除。
封装支付宝支付接口
把alipay_demo下文件直接拖到androidstudio工程中,需要如图这些文件:
对就是AuthResult、Base64、OrderInfoUtil2_0、PayResult、SignUtils这五个类即可,MainActivity创建时就有。
我们需要做的就是修改MainActivity这个类,其他都是工具定义相关的类,看下官方提供的注释就行。直接上代码了:
package com.xxl.youxigame;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.widget.Toast;
import com.unity3d.player.*;
import com.alipay.sdk.app.PayTask;
import java.util.Map;
public class MainActivity extends UnityPlayerActivity {
private static final int SDK_PAY_FLAG=1;
private static final int SDK_AUTH_FLAG = 2;
private static final String RESULT_SUCCESS="9000";
private static final String TIP_PAY_SUCCESS="支付成功";
private static final String TIP_PAY_FAILED="支付失败";
// 支付结果回调,仅作参考,以服务端确认为准!
@SuppressLint("HandlerLeak")
private Handler mHandler=new Handler(){
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what)
{
case SDK_PAY_FLAG:
{
@SuppressWarnings("unchecked")
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
String resultInfo = payResult.getResult();
String resultStatus = payResult.getResultStatus();
if (TextUtils.equals(resultStatus, RESULT_SUCCESS))
{
Toast.makeText(MainActivity.this, TIP_PAY_SUCCESS, Toast.LENGTH_SHORT).show();
} else
{
Toast.makeText(MainActivity.this, TIP_PAY_FAILED, Toast.LENGTH_SHORT).show();
}
break;
}
case SDK_AUTH_FLAG: {
@SuppressWarnings("unchecked")
AuthResult authResult = new AuthResult((Map<String, String>) msg.obj, true);
String resultStatus = authResult.getResultStatus();
// 判断resultStatus 为“9000”且result_code
// 为“200”则代表授权成功,具体状态码代表含义可参考授权接口文档
if (TextUtils.equals(resultStatus, "9000") && TextUtils.equals(authResult.getResultCode(), "200")) {
// 获取alipay_open_id,调支付时作为参数extern_token 的value
// 传入,则支付账户为该授权账户
Toast.makeText(MainActivity.this,
"授权成功\n" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT)
.show();
} else {
// 其他状态值则为授权失败
Toast.makeText(MainActivity.this,
"授权失败" + String.format("authCode:%s", authResult.getAuthCode()), Toast.LENGTH_SHORT).show();
}
break;
}
default:
break;
}
}
};
//这些参数根据自己实际情况填入,参见第一步配置中的官网文档链接
/** 支付宝支付业务:入参app_id */
public static final String APPID = "2017061500021222";
/** 支付宝账户登录授权业务:入参pid值 */
public static final String PID = "2088102123816631";
/** 支付宝账户登录授权业务:入参target_id值 */
public static final String TARGET_ID = "kkkkk091125";
//测试用的私钥
public static final String RSA2_PRIVATE = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJkhXBA/IH5uU8KcIw4p5x4i0zu+LZVAnff/z3Fd/JGc/iKrIFMJ+Gdkzd9lc9pM3pEkb8Hr7zuNb4YAZOYwxUJGt18IIhsr/DImCd+4hnbaP+X61jArJugnhV05zsI8IJtu4N6whpcHhB4RPKYB4VyFnyr6em6DqY0dXe7bdtm3AgMBAAECgYEAl7/ZbjhAyUooM2lry/N2mATG9COJJKl+Ym/dcWlEjEDaEB0p0WDGDCB3bHUrlCAtSASlw7U9xPRqmo71brDSKU0+PSSjpYPVk2rByL4rqWOhuJM/jz2LkdKhlDJLGu72JpdldA8WVKPpEYpDVUQHiWVVHQFR2u96p45uj2ExjRECQQDLbqmB/NLkJUNHisIzNHDijU+YO6fPN/7zDOlnRjhigY0gTTP4zGUbtFHuTHQsKP2suSNlPFWjlJ+6k4kjpV41AkEAwLMmc4eWsRJematJ03m98mtP6TahoRFvZ47KemAPVTDCjnLTk1n4bQ/4lgydzzSNn9YCUq/YxwWU+/dNZgQFuwJAdF8/lF5+fYhbbmeQJB6RnOfdamZl3oJX083FDxD6XE9j3eCMJH04MZr7a2hM5J4mT1IxT04uZz80CFUxlDSbKQJAfRfPblAm0uxJ3RgE5POzCxv+1DZS1myrFV7ssmSJj5QHuNFx58YQLzye80ldaJWFGq2i9GqTHx/Qh4ETDZau4QJBALFwmdH3I+f5/Fjkc9CNdMOJfdp6JP+vkMjS966IKbhk21PKwAkhmSSMx6CVFuATFovRrWD2YlXfu+4d8HXsTWM=";
public static final String RSA_PRIVATE = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
//Unity中调用
public void Pay(final String orderInfo)
{
if (TextUtils.isEmpty(APPID) || (TextUtils.isEmpty(RSA2_PRIVATE) && TextUtils.isEmpty(RSA_PRIVATE))) {
ShowToast("需要配置APPID | RSA_PRIVATE");
return;
}
//这里为了测试参数orderInfo并没有使用,而是直接拼接的orderInfo1
boolean rsa2 = (RSA2_PRIVATE.length() > 0);
Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2);
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);
final String orderInfo1 = orderParam + "&" + sign;
Runnable payRunnable=new Runnable() {
@Override
public void run() {
PayTask alipay=new PayTask(MainActivity.this);
Map<String,String> result=alipay.payV2(orderInfo1,true);
Message msg=new Message();
msg.obj=result;
mHandler.sendMessage(msg);
}
};
Thread payThead=new Thread(payRunnable);
payThead.start();
}
public void ShowToast(final String message)
{
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
});
}
}
注意:orderInfo可以在客户端生成,需要AppId,pid以及RSA等等,这样做不安全,推荐的做法是由服务端生成订单信息并加密(生成相关的逻辑在Demo里已经给出了),然后传递给客户端,客户端支付完成后,支付宝将执行一个配置好的URL,例如通知服务端支付完毕,而客户端在支付完成后提示支付成功与否的信息只能作为参考。
Unity中如何调用
unity中调用java有固定的方法,官方文档:https://docs.unity3d.com/ScriptReference/AndroidJavaObject.Call.html
直接上代码洛:
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
[System.Serializable]
public class PayInfo
{
public string subject; // 显示在按钮上的内容,跟支付无关系
public float money; // 商品价钱
public string title; // 商品描述
}
public class AlipayUI : MonoBehaviour
{
public List<Button> buttons = null;
public List<PayInfo> payInfos = null;
private AndroidJavaObject currentActivity = null;
void Start()
{
#if UNITY_ANDROID && !UNITY_EDITOR
// 固定写法
AndroidJavaClass javaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
currentActivity = javaClass.GetStatic<AndroidJavaObject>("currentActivity");
#endif
// Init UI
for (int i = 0; i < buttons.Count; i++)
{
var payInfo = payInfos[i];
buttons[i].GetComponentInChildren<Text>().text = payInfos[i].subject;
#if UNITY_ANDROID && !UNITY_EDITOR
buttons[i].onClick.AddListener(() =>
{
SHow();
AliPay(payInfo);
});
#endif
}
}
public void SHow()
{
currentActivity.Call("ShowToast", "Hello World!");
}
public void AliPay(PayInfo payInfo)
{
currentActivity.Call("Pay", "ddd");
}
}
上面这个类挂在MainCamera上就行,参数如下图配置:
选择Android平台打包测试即可,额,写文档好累啊。
附录
参考链接如下:
http://blog.csdn.net/zhangdi2017/article/details/63254563
http://www.voidcn.com/blog/qq_16131393/article/p-6168930.html
上一篇: Linux:cut命令详解 博客分类: linux
下一篇: JVM--垃圾回收--常见算法
推荐阅读
-
Unity Android平台接入支付宝
-
Android app第三方支付宝支付接入教程
-
Android 支付宝支付、微信支付、银联支付 整合第三方支付接入方法(后台订单支付API设计)
-
Android App支付系列(二):支付宝SDK接入详细指南(附官方支付demo)
-
Android 支付宝支付、微信支付、银联支付 整合第三方支付接入方法(后台订单支付API设计)
-
Android App支付系列(二):支付宝SDK接入详细指南(附官方支付demo)
-
Android 第三方应用接入微信平台研究情况分享(二)
-
Android 第三方应用接入微信平台研究情况分享(一)
-
Android 第三方应用接入微信平台研究情况分享(一)
-
Android 第三方应用接入微信平台研究情况分享(二)