中国移动动漫基地
|
开发指南
|
V 1.2
|
2013-11 |
本文档主要描述了中国移动动漫基地的短信计费基本机制,以及指导开发者如何在应用中使用应用内计费功能。文档中提供了开发者需要做哪些准备、如何获取所需资源及如何使用SDK等的指引,同时也提供了相关的范例供开发者学习使用。 |
目 录
2.1.3 OnSMSPaycodeListener中返回数据说明... 7
3.1 AndroidManifest.xml修改... 13
3.2 实现OnSMSPaycodeListener. 14
1.1 开发应用
1.1.1准备开发环境
在使用应用内计费接口之前,请确认Eclipse、JDK、Android SDK已经安装,并正常使用。如果尚未安装,请参考以下资源,安装过程不再赘述。
Eclipse:
http://www.eclipse.org/downloads/
JDK:
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Android SDK:
http://developer.android.com/SDK/index.html
1.1.2 下载和导入SDK
SDK以jar文件的形式提供给开发者在程序中使用,同时提供HTML格式的API文档供查阅相关类、方法、常量等说明。
以下内容将说明如何在Eclipse中,将jar文件加入到应用工程中去。
1. 将Cartoonsmsbilling1.0.0.jar文件拷贝到应用工程的libs目录下,如没有该目录,可新建;
2. 在ProjectExplorer中右击鼠标,从弹出的菜单中,选中“Properties”;
3. 在Properties窗口的左侧菜单项中,点击“Java Build Path”,并在右侧选中“Libraries”;
4. 点击“Add JARs…”按钮,在弹出窗口中,选中jar文件,如下图1所示。
图表 1 添加jar文件
最后,检查ReferencedLibraries中是否可以看到jar文件,如下图2所示。如果可以,则表示配置成功,否则,请检查上述步骤是否执行成功。
图表 2 检查
5. *将libdmsmsiap.so复制到libs\armeabi目录下
2.4.3 使用SDK
*SDK使用注意事项
使用SDK可依照以下五个步骤。
1) 实现OnSMSPaycodeListener
OnSMSPaycodeListener是应用内计费的监听器,检查的结果通过onBillingFinish返回给调用者。
以上这些方法中的参数StatusCode的取值,均定义在PurchaseCode类的常量中,包括AUTH_XXX和COPYRIGHT_XXX等,每个常量具体表达的含义,请参考API文档, 也可使用SMSPurchase.getDescription(int)方法获取具体描述。
2) 增加权限声明
打开应用的AndroidManifest.xml文件,增加权限
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
以确保可以正常读取手机的IMSI/IMEI。
1.2 开发者开发应用注意事项
1) 为保证自身敏感数据(APPID、APPKEY、PAYCODE)的安全性,请尽量采用加密等手段保存,避免以常量字符串形式出现于源码。
2) 为保护自身数据和付费点,开发完成后,建议对APK做混淆处理。
3) 应用中不能同时发起两起或者以上的订购操作,比如不能同时启动两个查询订单的线程。
4) 可重复购买的计费点,在两次订购之间,目前有时间限制(目前定义30秒钟)
5) 应用升级,开发如果需要升级目前已投入商用的APP,需要重新上传后,用户通过动漫基地或者其他与移动有关渠道升级。如果采用自升级,可能会因为APP数据与移动服务器中数据不一致,导致APP中无法正常发起交易业务。
6) 中国移动部分省份已经开始销售147号段的SIM卡,该号段同样可以使用IAP进行计费。请应用开发者注意判断此号段的SIM卡,以免造成不必要的麻烦。
2 应用内计费SDK使用手册
2.1 SDK组成和接口说明
SDK公开的接口包括:
2.1.1 SMSPaycodeAPI说明
SMSPaycode对象是SDK提供给开发者发起订购的接口。
开发者在实例化该对象后,调用其中的函数可以处理相应的业务。
1) 构造实例:
SMSPaycode对象的创建使用了单例模式,不需要重复创建:
SMSpurcode = SMSPaycode.getInstance(); |
2) 各参数设置:
SMSPaycode.setAppInfo(appid, appkey); // 设置计费应用ID和Key (必须) |
3) 订购:
传统接口:
调用SMSPurchase对象中的smsorder函数,传入相应的参数:
l payCode,计费点(见本文档2.3)
l Listener,本参数是开发实现OnSMSPaycodeListener对象的实例,主要用于监听各个业务的结果。
// 订购一个商品 SMSPaycode.smsorder(context, paycode, listener); |
订购具体的结果在OnSMSPaycodeListener中的onBillingFinish()中获得。
使用UserData接口:
l payCode,计费点(见本文档2.3)
l Listener,本参数是开发实现OnSMSPaycodeListener对象的实例,主要用于监听各个业务的结果。
l Userdata,开发者透传数据。
Userdata用于开发者上传的任意数据,该数据需要限制在16个字节以内。
// 订购一个商品 SMSPaycode.smsorder(context, paycode, listener,userdata); |
2.1.2 OnSMSPaycodeListener
应用内计费各种操作(初始化,订购)监听器。开发者通过实现该接口中各个接口来监听各种业务操作的状态:
// 订购返回接口: void onBillingFinish(final int returncode, final HashMap<String, Object> returnObject) |
Returncode的定义在PurchaseCode类中,具体含义可以通过getDescription()获取。
2.1.3 OnSMSPaycodeListener中返回数据说明
正如前面所描述的一样,初始化,订购接口的返回值在OnSMSPaycodeListener中得到。
returnObject中定义的数据主要有几种:
// 计费点代码 public final static String PAYCODE = "Paycode"; //交易ID public final static String PAYCODE = "TradeID";
|
上面这些值包含在onBillingFinish中参数Hashmap中。各个接口返回的数据不一样。
上面这些值所代表的意义如下:
Paycode,表示此次交易的计费点
TradeID,表示此次交易的id
1)订购接口
订购接口在订购成功后,会返回上面一个值。如果订购失败,则不返回上面任何值。
2.2 业务流程及要点说明
2.2.1 主要流程
初始化 |
订购 |
首次计费时,或者初始化,SDK会发送短信激活。之后,只要不失效,将不会再次触发。
2.3 SDK调用时序
2.3.1 订购
注意:
1. 本期SDK在触发订购之后,接管全部UI,所以应用在调用smsorder接口之后不需要做任何处理, 所有UI处理均已由SDK处理。
2. onBillingFinish()方法在订购界面退出后,才会返回给应用。
2.4 示例代码
下面将通过demo中的代码具体说明如何使用本SDK。
APPID,APPKEY,PayCode设置。
在demo程序中,APPID,APPKEY,PayCode默认赋值为00000000000。请根据在2.3节中操作,将生成的APPID,APPKEY,PayCode分别填入。
// 计费应用信息(demo测试)
private static final String APPID = "00000000000";
private static final String APPKEY = "00000000000";
// 计费点信息
private static final String LEASE_PAYCODE = "00000000000";// 单次
OnSMSPaycodeListener接口实现
开发者使用SDK,需要自定义实现一个接口OnSMSPaycodeListener,该接口用来将初始化,订购的结果或者状态返回给APP。Demo中具体实现如下:
public class IAPListener implements OnSMSPaycodeListener {
private final String TAG = "IAPListener";
private Demo context;
private IAPHandler iapHandler;
public IAPListener(Context context, IAPHandler iapHandler) {
this.context = (Demo) context;
this.iapHandler = iapHandler;
}
public void onBillingFinish(int code, HashMap arg1) {
Log.d(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,tradeID */
if (arg1 != null) {
paycode=(String)arg1.get(OnSMSPaycodeListener.PAYCODE);
if (paycode != null && paycode.trim().length()!= 0) {
result = result + ",Paycode:" + paycode;
}
tradeID=(String)arg1.get(OnSMSPaycodeListener.TRADEID);
if (tradeID != null && tradeID.trim().length()!= 0) {
result = result + ",tradeid:" + tradeID;
}
}
} else {
/**
* 表示订购失败。
*/
result = "订购结果:" + SMSPaycode.getReason(code);
}
context.dismissProgressDialog();
System.out.println(result);
}
SDK初始化
本SDK初始化很简单,只需要实例化SDK中SMSPaycode类即可,再根据APP的实际情况设置相应的参数。Demo中的代码如下:
@Override
public void onCreate(Bundle savedInstanceState){
/**
* IAP组件初始化.包括下面3步。
*/
/**
* step1.实例化OnSMSPaycodeListener。实例化传入的参数与您实现OnSMSPaycodeListener接口的对象有关。
* 例如,此Demo代码中使用IAPListener继承OnSMSPaycodeListener,其构造函数需要Context实例。
*/
mListener = new IAPListener(this, iapHandler);
/**
* step2.获取Purchase实例。
*/
purchase= SMSPaycode.getInstance();
/**
* step3.向Purhase传入应用信息。APPID,APPKEY。需要传入参数APPID,APPKEY。 APPID,见开发者文档
* APPKEY,见开发者文档
*/
try {
purchase.setAppInfo(APPID, APPKEY);
} catch (Exception e1) {
e1.printStackTrace();
}
}
SDK订购接口的调用
1)订购接口调用
订购只能可重复购买这种类型的订购,此版本应用内计费SDK包含有1个订购接口
1. 订购接口
public void smsOrder(Contextcontext, String paycode,OnSMSPaycodeListener listener)
需要传入Activity实例,paycode,以及OnSMSPaycodeListener的实例
3.4.1 应用混淆
如果您的应用需要混淆,请参照下面的格式修改proguard.cfg。然后使用ProGuard工具对您的应用进行混淆。
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-dontwarn
-dontnote
-verbose
-optimizations!code/simplification/arithmetic,!field/*,!class/merging/*
-libraryjarslibs/mmsmsbilling1.2.0.jar
-keep public class* extends android.app.Activity
-keep public class* extends android.app.Application
-keep public class* extends android.app.Service
-keep public class* extends android.content.BroadcastReceiver
-keep public class* extends android.content.ContentProvider
-keep public class* extends android.app.backup.BackupAgentHelper
-keep public class* extends android.preference.Preference
-keep public classcom.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context,android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context,android.util.AttributeSet, int);
}
-keepclassmembers enum* {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class *implements android.os.Parcelable {
public static finalandroid.os.Parcelable$Creator *;
}
-keep public class sms.purchasesdk.cartoon.OnSMSPaycodeListener{*;}
-keep public classsms.purchasesdk.cartoon.PurchaseCode {*;}
-keep public enumsms.purchasesdk.cartoon.OnSMSPaycodeListener$** {
**[]$VALUES;
public *;
}
具体修改如下,如果要混淆某个包,则在proguard.cfg中增加:
–keep class 应用某个包名.**
注意:您在混淆时,请务必在cfg文件中添加红色的代码,否则可以会导致您的程序运行出错。蓝色部分的代码,如果您使用eclipse工具混淆则需要添加,如果是ant编写的混淆脚本则不需要添加。
如果您使用ant脚本编译,可以参照build.xml中的混淆脚本修改您的脚本
<target name="optimize"depends="compile">
<echo>optimize classes are put to"${out.absolute.dir}" .</echo>
<jarbasedir="${out.classes.absolute.dir}"destfile="${out.absolute.dir}/temp.jar"/>
<javajar="${jar.proguard}\proguard.jar" fork="true"failοnerrοr="true">
<jvmargvalue="-Dmaximum.inlined.code.length=32"/>
<argvalue="@${jar.proguard}\proguard.cfg"/>
<argvalue="-injars ${out.absolute.dir}/temp.jar"/>
<argvalue="-outjars ${out.absolute.dir}/optimized.jar"/>
<argvalue="-libraryjars ${SDK.dir}/platforms/android-4/android.jar"/>
<argvalue="-libraryjars ./libs/mmsmsbilling1.2.0.jar"/>
</java>
<deletefile="${out.absolute.dir}/temp.jar"/>
<deletedir="${out.classes.dir}" failοnerrοr="false" />
<mkdirdir="${out.classes.dir}"/>
<unzipsrc="${out.absolute.dir}/optimized.jar"dest="${out.classes.absolute.dir}"/>
<deletefile="${out.absolute.dir}/optimized.jar"/>
</target>
Proguard的路径在local.properties中进行修改。Demo中有个文件夹proguard中存放的是proguard.jar文件和proguard.cfg
3 开发者集成弱联网计费版本教程
弱联网计费sdk版本使用到了android中的部分权限。因此,在集成弱联网计费sdk需要做如下一些工作
3.1 AndroidManifest.xml修改
3.1.1 添加receiver
<receiver android:name="sms.purchasesdk.cartoon.sms.SMSReceiver">
<intent-filter android:exported="false">
<action android:name="aspire.iap.SMS_SEND_ACTIOIN"/>
<action android:name="aspire.iap.SMS_DELIVERED_ACTION"/>
</intent-filter>
</receiver>
短信计费sdk需要在AndroidManifest.xml中注册一个receiver,这个receiver的作用是用来判断短信是否发送。
3.2 实现OnSMSPaycodeListener
OnSMSPaycodeListener的作用请参考3.1.3节的说明。本节仅说明如何在程序中实现这个接口 。
public class IAPListener implements OnSMSPaycodeListener{
private final String TAG = "IAPListener";
private Demo context;
private IAPHandler iapHandler;
public IAPListener(Context context, IAPHandler iapHandler) {
this.context = (Demo) context;
this.iapHandler = iapHandler;
}
@Override
public void onBillingFinish(int code, HashMap arg1) {
Log.d(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(OnSMSPaycodeListener.PAYCODE);
if (paycode != null && paycode.trim().length() != 0) {
result = result + ",Paycode:" + paycode;
}
tradeID = (String) arg1.get(OnSMSPaycodeListener.TRADEID);
if (tradeID != null && tradeID.trim().length() != 0) {
result = result + ",tradeid:" + tradeID;
}
}
} else {
/**
* 表示订购失败。
*/
result = "订购结果:" + SMSPaycode.getReason(code);
}
context.dismissProgressDialog();
System.out.println(result);
}
}
3.3 调用计费接口
具体调用可参考实例代码中3.4.1节 。