這篇文章前面講的創建Android Studio工程的流程是不正確的!!!
最近幫一個羣裏的朋友接了一下支付寶的SDK,開發環境是Unity 5.4.x + 最新的Android Studio2.3版本,最終Android Studio輸出的文件格式是aar而不是之前的jar,鑑於網上的文章大多數是基於Eclipse + jar包,所以記錄一下基於Android Studio進行開發的過程,供大家參考。
下載與整理支付寶SDK
首先下載最新的支付寶SDK,解壓縮後找到alipay_demo和alipay_sdk文件夾,它們分別是Eclipse demo工程和是支付寶的jar包。接下來的步驟的會用到這兩個文件夾裏的內容。
創建並配置Android Studio工程
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.soulgame.magicgame">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
這裏的android:icon,android:label,android:roundIcon和android:theme是不需要的,刪除它們。同時必須在<activity>標籤裏插入一行<meta-data>屬性,應該是Unity打包時Merge AndroidManifest時需要的,修改後如下所示:<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.soulgame.magicgame">
<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>
最後,因爲我們輸出的是一個庫而不是一個apk,所以需要修改輸出的結果,打開Gradle Scripts(Gradle是一種安卓構建腳本)下的build.gradle(Moudle:app),將第一行的:apply plugin: 'com.android.application'
修改爲:apply plugin: 'com.android.library'
點擊上方的sync now,會出現錯誤提示:接入支付寶SDK
首先我們需要引入支付寶SDK的jar包,將alipay_sdk下的alipaySdk-20XXXXXX.jar和Unity提供的jar包拷貝到項目路徑/app/libs文件夾下,Unity提供的jar包路徑是:然後回到AndroidStudio,菜單欄選擇File -> Project Structure界面,點擊app -> Dependencies如下圖所示:
點擊旁邊的減號,刪掉目前這三個以來庫,然後點擊加號 -> Jar Dependency,選擇剛纔拷貝到Libs下面的那兩個jar文件,點擊確定。可以發現build.gradle(Moudle:app)下depedencies裏出現了支付寶的Sdk jar包,完整的build.gradle如下:
apply plugin: 'com.android.library'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 9
targetSdkVersion 25
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile files('libs/alipaySdk-20170309.jar')
compile files('libs/classes.jar')
}
將debug修改爲release:
-libraryjars libs/alipaySDK-20XXXXXX.jar //這裏改成你所使用的SDK jar版本
-keep class com.alipay.android.app.IAlixPay{*;}
-keep class com.alipay.android.app.IAlixPay$Stub{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback{*;}
-keep class com.alipay.android.app.IRemoteServiceCallback$Stub{*;}
-keep class com.alipay.sdk.app.PayTask{ public *;}
-keep class com.alipay.sdk.app.AuthTask{ public *;}
研究支付寶給出的Demo可以發現,支付寶支付函數只需要一個加密後的訂單信息字符串:
public void Pay(final String orderInfo)
{
Runnable payRunnable = new Runnable()
{
@Override
public void run()
{
PayTask alipay = new PayTask(MainActivity.this);
Map<String, String> result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
orderInfo可以在客戶端生成,需要AppId,pid以及RSA等等,這樣做不安全,推薦的做法是由服務端生成訂單信息並加密(生成相關的邏輯在Demo裏已經給出了),然後傳遞給客戶端,客戶端支付完成後,支付寶將執行一個配置好的URL,例如通知服務端支付完畢,而客戶端在支付完成後提示支付成功與否的信息只能作爲參考。package com.soulgame.magicgame;
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.alipay.sdk.app.PayTask;
import com.unity3d.player.*;
import java.util.Map;
public class MainActivity extends UnityPlayerActivity
{
private static final int SDK_PAY_FLAG = 1;
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;
}
default:
break;
}
}
;
};
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
// Unity中調用
public void Pay(final String orderInfo)
{
Runnable payRunnable = new Runnable()
{
@Override
public void run()
{
PayTask alipay = new PayTask(MainActivity.this);
Map<String, String> result = alipay.payV2(orderInfo, true);
Message msg = new Message();
msg.what = SDK_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
Thread payThread = new Thread(payRunnable);
payThread.start();
}
}
在Unity中進行調用
在Assets下創建Plugins文件夾,然後在Plugins下創建Android文件夾,將aar和AndroidManifest.xml文件複製到該文件夾下。使用起來可以參考Unity官方文檔。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()
{
// 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(() =>
{
Alipay(payInfo);
});
#endif
}
#if UNITY_ANDROID && !UNITY_EDITOR
// 固定寫法
AndroidJavaClass javaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
currentActivity = javaClass.GetStatic<AndroidJavaObject>("currentActivity");
#endif
}
public void Alipay(PayInfo payInfo)
{
// AlipayClient是Android裏的方法名字,寫死.
// payInfo.money是要付的錢,只能精確分.
// payInfo.title是商品描述信息,注意不能有空格.
currentActivity.Call("AlipayClient", payInfo.money, payInfo.title, "");
}
}
運行結果: