不得不说移动mm平台是比较友好的,遇到的所有问题都在群里有人回答,并且sdk接入十分方便,没有遇到什么大问题。
工作量大概是一天左右,分享一下接入过程。
所需环境:
AIR:3.9
ANDROIDAPI:19
移动mm版本:1.2.2
1.编写as文件
定义函数常量
private static const MM_FUNCTION_INIT:String = "mmsns_function_init";//与java端中Map里的key一致
private static const MM_FUNCTION_BILL:String = "mmsns_function_bill";//与java端中Map里的key一致
private static const MM_FUNCTION_DEBUG:String = "mmsns_function_debug";//与java端中Map里的key一致
private static const EXTENSION_ID:String = "com.mmsns.ane";//与extension.xml中的id标签一致
private static var _instance:MMSNSExtension;
public function MMSNSExtension()
{
if(extContext == null) {
extContext = ExtensionContext.createExtensionContext(EXTENSION_ID, "");
extContext.addEventListener(StatusEvent.STATUS, statusHandler);
}
}
/**
* 获取实例
* @return DLExtension 单例
*/
public static function getInstance():MMSNSExtension
{
if(_instance == null) {
_instance = new MMSNSExtension();
}
return _instance;
}
/**
* 转抛事件
* @param event 事件
*/
private function statusHandler(event:StatusEvent):void
{
dispatchEvent(event);
}
以上是99%的ane都需要复制粘贴的语句。。
然后是定义移动mm的函数,因为弱联网版本只有初始化跟支付两个功能点,所以直接写
/**
* 初始化
* @param APPID
* @param APPKEY
* @return
*
*/
public function MMSNSInit(APPID:String,APPKEY:String):void{
if(extContext ){
extContext.call(MM_FUNCTION_INIT, APPID, APPKEY);
}
}
/**
* 商品购买接口。
* @param payCode
* @param num
* @param description
* @return
*
*/
public function MMSNSBilling(payCode:String, num:uint, description:String = ''):void{
if(extContext ){
extContext.call(MM_FUNCTION_BILL, payCode, num, description);
}
}
以上,as版本真心没技术含量,请大家谅解。
然后是安卓端。。
安卓端我的api一律设为19,然后记得勾上"Mark this project as a library",上面两项都去掉勾
安卓端要先创建context跟extension两个文件,把入口代码站过去。
Context文件
package com.mmsns.ane;
import java.util.HashMap;
import java.util.Map;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.mmsns.func.MMSNSBill;
import com.mmsns.func.MMSNSBillInit;
public class MMSNSContext extends FREContext {
/**
* 初始化
*/
public static final String MMSNS_FUNCTION_INIT = "mmsns_function_init";
/**
* 订购
*/
public static final String MMSNS_FUNCTION_BILL = "mmsns_function_bill";
@Override
public void dispose() {
// TODO Auto-generated method stub
}
@Override
public Map<String, FREFunction> getFunctions() {
// TODO Auto-generated method stub
Map<String, FREFunction> map = new HashMap<String, FREFunction>();
//映射
map.put(MMSNS_FUNCTION_INIT, new MMSNSBillInit());
map.put(MMSNS_FUNCTION_BILL, new MMSNSBill());
return map;
}
}
Extension文件
package com.mmsns.ane;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREExtension;
public class MMSNSExtension implements FREExtension {
@Override
public FREContext createContext(String arg0) {
// TODO Auto-generated method stub
return new MMSNSContext();
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
@Override
public void initialize() {
// TODO Auto-generated method stub
}
}
把入口定义好后,就是加入功能代码了,因为要完成移动mm的支付,需要完成Handler和OnSMSPurchaseListener这两个类来监测初始化跟支付的状态。
IAPHandler
package com.mmsns.func;
import android.os.Handler;
import android.os.Message;
import com.adobe.fre.FREContext;
public class IAPHandler extends Handler {
public static final int INIT_FINISH = 10000;
public static final int BILL_FINISH = 10001;
public static final int QUERY_FINISH = 10002;
public static final int UNSUB_FINISH = 10003;
public IAPHandler(FREContext context) {
MMSNSShared.context = (FREContext) context;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}
IAPListener,处理各种完成的回调之类的,抛送信息到as端
package com.mmsns.func;
import java.util.HashMap;
import mm.sms.purchasesdk.OnSMSPurchaseListener;
import mm.sms.purchasesdk.PurchaseCode;
import mm.sms.purchasesdk.SMSPurchase;
import android.os.Message;
import android.util.Log;
import com.adobe.fre.FREContext;
public class IAPListener implements OnSMSPurchaseListener {
private final String TAG = "IAPListener";
private IAPHandler iapHandler;
public IAPListener(FREContext context, IAPHandler iapHandler) {
MMSNSShared.context = context;
this.iapHandler = iapHandler;
}
@Override
public void onInitFinish(int code) {
MMSNSShared.event(TAG, "Init finish, status code = " + code);
Message message = iapHandler.obtainMessage(IAPHandler.INIT_FINISH);
String result = "初始化结果:" + SMSPurchase.getReason(code);
message.obj = result;
message.sendToTarget();
}
@Override
public void onBillingFinish(int code, HashMap arg1) {
MMSNSShared.event(TAG, "billing finish, status code = " + code);
String result = "订购成功";
Message message = iapHandler.obtainMessage(IAPHandler.BILL_FINISH);
// 商品信息
String paycode = null;
// 商品的交易 ID,用户可以根据这个交易ID,查询商品是否已经交易
String tradeID = null;
if (code == PurchaseCode.ORDER_OK
|| code == PurchaseCode.ORDER_OK_TIMEOUT) {
/**
* 商品购买成功或者已经购买。 此时会返回商品的paycode,orderID,以及剩余时间(租赁类型商品)
*/
if (arg1 != null) {
paycode = (String) arg1.get(OnSMSPurchaseListener.PAYCODE);
if (paycode != null && paycode.trim().length() != 0) {
result = result + ",Paycode:" + paycode;
}
tradeID = (String) arg1.get(OnSMSPurchaseListener.TRADEID);
if (tradeID != null && tradeID.trim().length() != 0) {
result = result + ",tradeid:" + tradeID;
}
MMSNSShared.event("ORDER_SUCCESS", paycode);
}
} else {
/**
* 表示订购失败。
*/
result = "订购失败:" + SMSPurchase.getReason(code);
MMSNSShared.event("ORDER_FAIL", SMSPurchase.getReason(code));
Log.d(TAG, "ORDER_FAIL" + SMSPurchase.getReason(code));
}
MMSNSShared.event(TAG, result);
}
}
好了,现在可以开始写功能函数了,但是我们需要一个共享的类来存储context和一些初始信息,方便我们随时调用。
于是来一个Shared类,专门存储信息
package com.mmsns.func;
import mm.sms.purchasesdk.SMSPurchase;
import android.util.Log;
import android.widget.Toast;
import com.adobe.fre.FREContext;
public class MMSNSShared {
public static Boolean DEBUG = false;
public static String APPID = "0000000000";
public static String APPKEY = "0000000000";
public static SMSPurchase purchase;
public static IAPListener mListener;
public static FREContext context;
public static void event(String code,String level ){
Log.d(code, "---------抛出event-------" + ":"+level );
context.dispatchStatusEventAsync(code, level );
if (DEBUG){
Toast.makeText(context.getActivity(), code + ":" + level, Toast.LENGTH_LONG).show();
}
}
}
现在实现初始化mm模块
package com.mmsns.func;
import mm.sms.purchasesdk.SMSPurchase;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;
public class MMSNSBillInit implements FREFunction {
private String TAG = "MMBillInit";
@Override
public FREObject call(final FREContext context, FREObject[] arg1) {
MMSNSShared.context = context;
FREObject result = null;
try
{
MMSNSShared.APPID = arg1[0].getAsString();
MMSNSShared.APPKEY = arg1[1].getAsString();
}
catch(Exception e)
{
return null;
}
IAPHandler iapHandler = new IAPHandler(MMSNSShared.context);
/**
* IAP组件初始化.包括下面3步。
*/
/**
* step1.实例化PurchaseListener。实例化传入的参数与您实现PurchaseListener接口的对象有关。
* 例如,此Demo代码中使用IAPListener继承PurchaseListener,其构造函数需要Context实例。
*/
MMSNSShared.mListener = new IAPListener(MMSNSShared.context, iapHandler);
/**
* step2.获取Purchase实例。
*/
MMSNSShared.purchase = SMSPurchase.getInstance();
/**
* step3.向Purhase传入应用信息。APPID,APPKEY。 需要传入参数APPID,APPKEY。 APPID,见开发者文档
* APPKEY,见开发者文档
*/
try {
MMSNSShared.purchase.setAppInfo(MMSNSShared.APPID, MMSNSShared.APPKEY);
} catch (Exception e1) {
return null;
}
/**
* step4. IAP组件初始化开始, 参数PurchaseListener,初始化函数需传入step1时实例化的
* PurchaseListener。
*/
try {
MMSNSShared.purchase.smsInit(context.getActivity(), MMSNSShared.mListener);
} catch (Exception e) {
return null;
}
//--------------------------------
return result;
}
}
然后是支付函数
package com.mmsns.func;
import android.content.Context;
import com.adobe.fre.FREContext;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREObject;
public class MMSNSBill implements FREFunction {
private String TAG = "MMSNSBill";
@Override
public FREObject call(final FREContext context, FREObject[] arg1) {
String payCode = null,description = null;
int num = 0;
FREObject result = null;
//get params
try{
payCode = arg1[0].getAsString();
num = arg1[1].getAsInt();
description = arg1[2].getAsString();
}catch(Exception e){
MMSNSShared.event(TAG, "参数错误:" + e.getMessage() + "|" + payCode + "|" + num + description);
return null;
}
/**
* 商品购买接口。
*/
if(MMSNSShared.context != null){
order(MMSNSShared.context.getActivity(), payCode, num, description);
}else{
}
//--------------------------------
return result;
}
public void order(Context context, String payCode, int num, String description) {
try {
MMSNSShared.purchase.smsOrder(context, payCode, MMSNSShared.mListener, description);
} catch (Exception e) {
MMSNSShared.event(TAG, "支付失败" + e.getMessage() + "," + e.toString());
}
}
}
好了,程序上的东西都做好了,现在开始打包ane
我们需要as端bin文件夹下的swc文件,和and端bin文件夹下的jar文件
以及一个extension.xml的文件
<?xml version="1.0" encoding="UTF-8"?>
<extension xmlns="http://ns.adobe.com/air/extension/3.9">
<id>com.mmsns.ane</id>
<versionNumber>1</versionNumber>
<platforms>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>mmsnsbillingane.jar</nativeLibrary>
<initializer>com.mmsns.ane.MMSNSExtension</initializer>
<finalizer>com.mmsns.ane.MMSNSExtension</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
先要合并生成的jar跟移动的jar文件
用winrar之类的打开自己的jar和移动mm的jar,把移动mm的除了assets和META-INF外都复制到自己的jar文件那
我是使用批处理完成这个复杂的操作。。感谢前人的努力写出这段神奇的批处理
rem 你做的主JAR包的路径
set SOURCEJAR=com.mmsns.ane.jar
set MainJar=mmsnsbillingane.jar
rem 第三方JAR包的路径
set ExternalJar=mmsmsbilling1.2.2.jar
rem 第三方JAR包顶级包名称
set packageName=com
set packageName2=mm
rem swc文件名
set SWC=MMANE-SNS.swc
echo =========== start make jar ==============
rem 创建临时目录
md temp
rem 拷贝临时文件
rem copy %SOURCEJAR% %MainJar%
copy .\android-project\bin\%SOURCEJAR% .\temp\%MainJar% >nul
copy .\SDK1.2.2\libs\%ExternalJar% .\temp\ >nul
cd temp
rem 解压第三方包
jar -xf %ExternalJar%
rem 合并主JAR包
jar -uf %MainJar% %packageName%
rem 合并其他顶级包
jar -uf %MainJar% %packageName2%
然后把生成的jar,swc解压出来的catalog.xml,library.swf,一起扔到android-ARM文件夹里,把swc,extension.xml,p12放到外面
移动mm提供的libsmsiap.so,需要放到android-ARM/libs/armeabi-v7a下面
set FLEX_SDK=D:\AIR_3.9
java -jar "%FLEX_SDK%\lib\adt.jar" -package -storetype PKCS12 -keystore czq.p12 -storepass 123456 -target ane com.mmsns.ane extension.xml -swc *.swc -platform Android-ARM -C Android-ARM mmiap .
搞定。。
另外打包apk的时候,记得把移动mm的jar包里的assets\mmiap打包进你的apk。
我还做了个一件打包生成ane的自动化批处理文件,包含在源码里面。
本教程的所有代码以及打包函数都在这里。
https://github.com/platformanes/android-mm-sms
第一篇文章,请拍砖。感谢Rect的先期研究。接下来我会放出小米还有移动mm平台,以及我接过的一些ios平台的教程。有些rect的版本改动不大的我就不放出来了,请自己到https://github.com/platformanes去下载。
希望使用air的人能更专注于开发游戏上面,而不要在ane接入上耗费太多时间。