×
Namespaces

Variants
Actions
Revision as of 15:07, 18 July 2012 by hamishwillee (Talk | contribs)

程序内支付(IAP)-Midlet例子解析

From Nokia Developer Wiki
Jump to: navigation, search
WP Metro Icon Chinese.png
Article Metadata

文章
Amazing110 在 11 Jan 2012 创建
最后由 hamishwillee 在 18 Jul 2012 编辑

例子介绍

本文解析的例子是一个坦克游戏,用户下载后有两关可以试玩,如果要继续后面的关卡,就在本游戏中通过IAP购买。 你可以从这里下载该BattleTank游戏源码。
BattleTank-IAP.png Tank-IAP-mainview.JPG Tank-IAP-mainview-buy.JPG

IAP相关代码分析

IAP被添加到了这个坦克游戏中,通过它你可以你可以以一种简单的方式集成OVI商店购买功能到你的Java应用。 坦克游戏使用RecordStore 保存了一个布尔值,它表明了当前应用是否已经被购买。另外一种判断是否购买的方式是读取DRM保护的资源然后捕获IO异常,如果不能读取抛出该异常。这种方式的好处是在每次运行游戏时,不需要复位。

1. 实现接口-监听IAP支付事件

import com.nokia.mid.payment.IAPClientPaymentException;
import com.nokia.mid.payment.IAPClientPaymentListener;
import com.nokia.mid.payment.IAPClientPaymentManager;
import com.nokia.mid.payment.IAPClientProductData;
import com.nokia.mid.payment.IAPClientUserAndDeviceData;
..............
public class Main extends MIDlet implements IAPClientPaymentListener {
public static final String PURCHASE_ID = "681803";
private static boolean trial = true;
private static IAPClientPaymentManager manager;
private static Display display;
private BattleTankCanvas battleTankCanvas = null;

-这里有一种重要的成员变量,private static boolean trial = true; 这个成员就是用来标示,目前版本的是试用版还是已付费版的。 -另外一个重要成员就是“IAPClientPaymentManager manager”,基本上所有支付相关的实际操作都是靠它来完成的。 从上面的代码我们可以我们实现了一个很重要的接口“IAPClientPaymentListener ”,它提供了对IAPClientPaymentProvider相关事件的监听,你的程序需要实现和这个接口别且注册到IAPClientPaymentProvider,当相应的事件发生时以便获得异步的调用。 它定义了如下一些回调接口:

  • void productDataReceived(int status, IAPClientProductData pd)
  • void productDataListReceived(int status, IAPClientProductData[] productDataList)
  • void purchaseCompleted(int status, java.lang.String purchaseTicket)
  • void restorationCompleted(int status, java.lang.String purchaseTicket)
  • void restorableProductsReceived(int status, IAPClientProductData[] productDataList)
  • void userAndDeviceDataReceived(int status, IAPClientUserAndDeviceData ud)

在该例子中:

   public void userAndDeviceDataReceived(int status, IAPClientUserAndDeviceData ud) {}
public void restorableProductsReceived(int status, IAPClientProductData[] productDataList) {}
public void productDataListReceived(int status, IAPClientProductData[] productDataList) {}
 
public void productDataReceived(int status, IAPClientProductData pd) {
if(status == OK) BuyMenu.setPrice(pd.getPrice());
}
 
public void purchaseCompleted(int status, String purchaseTicket) {
battleTankCanvas.hideBuyMenuWaitIndicator();
if(status == OK) {
setTrial(false);
battleTankCanvas.hideBuyOption();
battleTankCanvas.hideBuyMenu();
} else {
showAlertMessage("Purchase failure", "Purchase process failed. "
+ Messages.getPaymentError(status), AlertType.ERROR);
}
}
 
public void restorationCompleted(int status, String purchaseTicket)
{
battleTankCanvas.hideBuyMenuWaitIndicator();
if(status == OK) {
setTrial(false);
battleTankCanvas.hideBuyOption();
battleTankCanvas.hideBuyMenu();
} else {
showAlertMessage("Restoraiton failure", "Restoration failed. "
+ Messages.getPaymentError(status), AlertType.ERROR);
}
}

我们可以从回调productDataReceived()的参数IAPClientProductData 中获取到价格。 当支付完成后,回调函数purchaseCompleted()会被调用,这时程序设定成员“trival”为false,同时把“Buy”从菜单中隐藏。



2. 获取实例,别且注册监听

    public void startApp() {
if(battleTankCanvas == null) {
battleTankCanvas = new BattleTankCanvas(this);
display = Display.getDisplay(this);
display.setCurrent(battleTankCanvas);
}
manager = getIAPManager();
manager.setIAPClientPaymentListener(this);
 
// If the trial flag has not been set to false in record store,
// query the status through In-app Puchase API. The boolean gets
// set during the instantiation of battleTankaCanvas
if(trial) {
manager.getProductData(PURCHASE_ID);
}
}

通过IAPClientPaymentManager.getIAPClientPaymentManager();我们就获取到了一个IAPClientPaymentManager的实例,别且通过manager.setIAPClientPaymentListener(this);设置回调监听。


3. 获取当前应用的相关信息

        if(trial) {
manager.getProductData(PURCHASE_ID);
}

我们通过IAPClientPaymentManager获取参数PURCHASE_ID所指定的应用的相关信息,以便后面的使用,当信息回去成功后,函数listener中的productDataReceived()会被调用。


4. 点击“BUY”按钮 当我们单击“BUY”按钮时,上面的函数将会被调用:

    public static boolean purchaseFullVersion() {
int status = manager.purchaseProduct(PURCHASE_ID,
IAPClientPaymentManager.FORCED_AUTOMATIC_RESTORATION);
if(status != IAPClientPaymentManager.SUCCESS)
{
showAlertMessage(display, "Purchase failure", "Purchase process failed. "
+ Messages.getPaymentError(status), AlertType.ERROR);
return false;
}
return true;
}

我们通过IAPClientPaymentManager::purchaseProduct(PURCHASE_ID, IAPClientPaymentManager.FORCED_AUTOMATIC_RESTORATION);实现商品的购买。 其中PURCHASE_ID就是该引用在Nokia'商店注册时得到的一个唯一的ID,第二参数是一些flag, 有NO_FORCED_RESTORATION 和 FORCED_AUTOMATIC_RESTORATION 可选。


5. 解锁付费关卡 代码如下:

    public static Image getImage(int level) throws ProtectedContentException, IOException {
System.out.println(Main.isTrial());
String fileName = fileNames[(level-1)%fileNames.length];
if(level <= 2) {
return Image.createImage(PATH + fileName);
} else if (Main.isTrial()) {
throw new ProtectedContentException();
} else {
try {
InputStream input = Main.getIAPManager().getDRMResourceAsStream(DRM_PATH+Main.PURCHASE_ID+"/"+fileName);
return Image.createImage(input);
} catch(Exception e) {
throw new IOException();
}
}
}

从上面的代码我们可以看到,当关卡小于等于2时,我们可以直接返回关卡的Image,当大于2时,我们需要判断是否已经付费,如果付费然后通过 IAPClientPaymentManager::getDRMResourceAsStream()获取并返回所需的被DRM封装的关卡资源。

相关链接

86 page views in the last 30 days.