今天跟大家一起看看UC支付,UC支付与其他支付不同之处在于:UC支付结果是发送到游戏服务器端的,所以我们在完成支付后需要询问服务器端支付是否成功,当确定支付成功后再执行相应的逻辑。
UC接入需要注意的事项比较多:
1.UC需要修改桌面游戏Logo,在游戏图标基础上加上UC的“9”图标,规范及样例会在百度网盘中为大家共享。
2.需要引入91SDK_LibProject工程作为Library。
3.搭建服务器用来接收UC返回来的支付结果(服务器端接入文档及demo会在网盘中跟大家共享,我这里没有搭建服务器端环境,无法给大家演示)。
4.支付数据存到本地,以便标识是否支付成功。
网盘地址:http://pan.baidu.com/share/link?shareid=438930&uk=473193131
这里跟大家一起看下如何将一个工程作为Library及供其它工程引用:
1.将91SDK_LibProject作为一个正常工程引入
2.然后我们看到这里果断打着个红叹号,这意味着有工程文件缺失,右击项目->Properties->Java Build Path ->Source,看到这里src is missing此工程用不到Java代码所以这个直接删掉就行,然后Clean项目。
图 1-1
3.红叹号没有了,然后在图1-1界面选择左侧边栏的Android,勾选Is Library确定
3.右击需要引入次工程的工程(即需要接入付费SDK的工程),选择properties,选Add将刚才作为Library的工程
引入进来
4.当你看到Android Dependencies下有了引入的工程那么工程作为Library引入完毕,如果没有的话刷新一下Clean一下,如果还没有那么说明引入过程有问题,重新来一遍
下边来看下代码:
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.blogforuc.uc" 此处要加上.uc的标识
android:versionCode="1"
android:versionName="1.0" >
<!-- UC -->
<service android:name="com.catcap.MyService"></service>
<activity
android:name="ucgamesdk.example.ApiGameDataActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent"
android:windowSoftInputMode="adjustResize" >
</activity>
<activity
android:name="cn.uc.gamesdk.view.SdkWebActivity"
android:configChanges="keyboardHidden|orientation"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent"
android:windowSoftInputMode="adjustResize" >
</activity>
<meta-data android:value="cn" android:name="APP_LANGUAGE"/>
<meta-data android:value="channel1" android:name="UMOB_CHID"/>
<meta-data android:value="XXXX" android:name="UMOB_APPKEY"/>//此处填写自己申请的
<!-- UC广告 -->
<activity android:name="cn.umob.android.ad.UMOBActivity" android:theme="@android:style/Theme.Translucent">
</activity>
<!-- UC -->
Fiap.java:支付接口初始化及支付
package com.example.blogforuc.uc;
import cn.uc.gamesdk.UCCallbackListener;
import cn.uc.gamesdk.UCCallbackListenerNullException;
import cn.uc.gamesdk.UCGameSDK;
import cn.uc.gamesdk.UCGameSDKStatusCode;
import cn.uc.gamesdk.UCLogLevel;
import cn.uc.gamesdk.info.GameParamInfo;
import cn.uc.gamesdk.info.OrderInfo;
import cn.uc.gamesdk.info.PaymentInfo;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
public class Fiap extends Activity {
// ===================================
// JAVA
// ===================================
// 以下参数仅供测试。在正式集成SDK时,需要使用正式的id数据。
// 游戏开发人员需要跟自己的商务或运营人员联系获取。
public int cpId = 3;
public int gameId = 3;
public int serverId = 5;
private int catcapcoin;
// 调试模式,此处联调模式时需要置为true
public boolean debugMode = false;
private MyDBHelper helper;
private SQLiteDatabase db;
private Intent intent;
private Dialog dialog;
private MyHandler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(Fiap.this, MyService.class);
this.startService(intent);
handler = new MyHandler();
findViewById(R.id.button1).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
android_pay(0);
}
});
}
public void android_pay(int catcap_coin) {
switch (catcap_coin) {
case 0:
catcapcoin = 2;
break;
case 1:
catcapcoin = 4;
break;
case 2:
catcapcoin = 6;
break;
case 3:
catcapcoin = 8;
break;
case 4:
catcapcoin = 10;
break;
case 5:
catcapcoin = 12;
break;
case 6:
catcapcoin = 14;
break;
}
ucNetworkAndInitUCGameSDK();
}
public void ucNetworkAndInitUCGameSDK() {
// !!!在调用SDK初始化前进行网络检查
// 当前没有拥有网络
if (false == isNetworkAvailable(this)) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt("what", 3);
msg.setData(bundle);
handler.sendMessage(msg);
} else {
ucSdkInit(); // 执行UCGameSDK初始化
}
}
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null && info.getState() == NetworkInfo.State.CONNECTED)
return true;
return false;
}
private void ucSdkInit() {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt("what", 0);
msg.setData(bundle);
handler.sendMessage(msg);
try {
GameParamInfo gpi = new GameParamInfo();
gpi.setCpId(cpId);
gpi.setGameId(gameId);
gpi.setServerId(serverId);
UCGameSDK.defaultSDK().initSDK(getApplicationContext(),
UCLogLevel.DEBUG, debugMode, gpi,
new UCCallbackListener<String>() {
@Override
public void callback(int code, String msg) {
Message msg2 = new Message();
Bundle bundle = new Bundle();
bundle.putInt("what", 1);
msg2.setData(bundle);
handler.sendMessage(msg2);
Log.e("UCGameSDK", "UCGameSDK初始化接口返回数据 msg:" + msg
+ ",code:" + code + ",debug:" + debugMode
+ "\n");
switch (code) {
// 初始化成功,调用登录
case UCGameSDKStatusCode.SUCCESS:
// 调用sdk登录接口
ucSdkLogin();
break;
// 初始化失败
case UCGameSDKStatusCode.INIT_FAIL:
ucNetworkAndInitUCGameSDK();
default:
break;
}
}
});
} catch (UCCallbackListenerNullException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void ucSdkLogin() {
try {
// 登录接口回调。从这里可以获取登录结果。
UCCallbackListener<String> loginCallbackListener = new UCCallbackListener<String>() {
@Override
public void callback(int code, String msg) {
Message msg2 = new Message();
Bundle bundle = new Bundle();
bundle.putInt("what", 1);
msg2.setData(bundle);
handler.sendMessage(msg2);
Log.e("UCGameSDK", "UCGameSdk登录接口返回数据:code=" + code
+ ",msg=" + msg);
// 登录成功。此时可以获取sid。并使用sid进行游戏的登录逻辑。
if (code == UCGameSDKStatusCode.SUCCESS) {
System.out.println("UCGameSDK SUCCESS");
payMoney();
}
// 登录失败。应该先执行初始化成功后再进行登录调用。
if (code == UCGameSDKStatusCode.NO_INIT) {
System.out.println("UCGameSDK NO_INIT");
}
// 登录退出。该回调会在登录界面退出时执行。
if (code == UCGameSDKStatusCode.LOGIN_EXIT) {
System.out.println("UCGameSDK LOGIN_EXIT");
}
}
};
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putInt("what", 0);
msg.setData(bundle);
handler.sendMessage(msg);
UCGameSDK.defaultSDK().login(Fiap.this, loginCallbackListener);
} catch (UCCallbackListenerNullException e) {
e.printStackTrace();
}
}
private void payMoney() {
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setRoleId(""); // 用户角色id
paymentInfo.setRoleName(""); // 角色名字
paymentInfo.setGrade(""); // 角色等级
paymentInfo.setCustomInfo(""); // 游戏自定义信息
// 服务器分区id
paymentInfo.setServerId(0);
// 通过设置参数会有以下效果:
// 当amount <= 0.0时,正常支付
// 当amount > 0.0时,使用定额支付
paymentInfo.setAmount(catcapcoin);
// 是否允许连续充值,这个在SDK2.1.0后不起作用
paymentInfo.setAllowContinuousPay(false);
try {
UCGameSDK.defaultSDK().pay(Fiap.this, paymentInfo,
new UCCallbackListener<OrderInfo>() {
@Override
public void callback(int statudcode, OrderInfo orderInfo) {
String texts = "";
switch (statudcode) {
case UCGameSDKStatusCode.SUCCESS:
helper = new MyDBHelper(Fiap.this,
"orderinfo.db", null, 1);
db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("orderid", orderInfo.getOrderId());
values.put("flag", "paying");
db.insert("orderinfo", null, values);
helper.close();
db.close();
break;
case UCGameSDKStatusCode.NO_INIT:
texts += "UCGameSDK调用支付接口失败,未初始化" + "\n";
Log.e("UCGameSDK", texts);
break;
case UCGameSDKStatusCode.PAY_USER_EXIT:
texts += "UCGameSDK支付界面退出" + "\n";
Log.e("UCGameSDK", texts);
break;
default:
break;
}
}
});
} catch (Exception e) {
Log.e("UCGameSDK", "UCGameSDK支付接口调用异常", e);
}
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
Bundle b = msg.getData();
int what = b.getInt("what");
switch (what) {
case 0:
dialog = ProgressDialog.show(Fiap.this, "", "请稍后,正在加载");
dialog.setCancelable(false);
break;
case 1:
dialog.cancel();
break;
case 3:
AlertDialog.Builder ab = new AlertDialog.Builder(Fiap.this);
ab.setMessage("网络未连接,请设置网络");
ab.setPositiveButton("设置",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
Intent intent = new Intent(
"android.settings.SETTINGS");
startActivityForResult(intent, 0);
}
});
ab.setNegativeButton("退出",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
}
});
ab.show();
break;
}
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
this.stopService(intent);
}
}
MyService.java:查询订单是否支付成功并完成支付成功的后续逻辑
package com.example.blogforuc.uc;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import android.app.Service;
import android.content.ContentValues;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service{
private String m_amount = "";
private MyDBHelper helper;
private SQLiteDatabase db;
//是否终止线程的标志,当程序执行OnDestory的时候需要置为false
private boolean flag;
//此处填写查询订单是否支付成功的服务器地址
private String url = "";
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
flag = true;
Thread th = new Thread(new myThread());
th.start();
}
class myThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
while(flag){
helper = new MyDBHelper(getApplicationContext(), "orderinfo.db", null, 1);
db = helper.getWritableDatabase();
//查询出未支付成功的订单
Cursor cursor = db.query("orderinfo", null, "flag = ?", new String[]{"paying"}, null, null, null);
if (null!=cursor) {
while(cursor.moveToNext()){
String id_order = cursor.getString(1);
if (null!=id_order) {
if (isSuccess(id_order)) {
if (null!=m_amount) {
//这里填写支付成功后的逻辑,并将数据库里的对应记录置为payed
// Layer.pay(catcapcoin);
ContentValues values = new ContentValues();
values.put("flag", "payed");
db.update("orderinfo", values, "orderid = ?", new String[]{id_order});
}
}
}
}
}
helper.close();
db.close();
try {
Thread.sleep(60000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//询问服务器订单是否支付成功
private boolean isSuccess(String id_order){
try {
String str = id_order
+ "gGoXQmgHA42egR";//gGoXQmgHA42egR为secret可以自己设置也可不写,主要是考虑数据安全性
String md5_sign = MD5(str);
HttpGet httpRequest = new HttpGet(url);
String strResult = "";
// HttpClient对象
HttpClient httpClient = new DefaultHttpClient();
// 获得HttpResponse对象
HttpResponse httpResponse = httpClient
.execute(httpRequest);
if (httpResponse
.getStatusLine()
.getStatusCode() == HttpStatus.SC_OK) {
// 取得返回的数据
strResult = EntityUtils
.toString(httpResponse
.getEntity());
}
//构造解析JSON数据对象
JSONObject jsonObj = new JSONObject(strResult);
//此处都是我项目中用到的参数在这里做个实例,请自行配置
String m_status = jsonObj.getString("status");
String m_sign = jsonObj.getString("sign");
String m_orderId = jsonObj.getString("orderId");
String m_ucid = jsonObj.getString("ucid");
m_amount = jsonObj.getString("amount");
Log.d("UCGameSDK","支付结果获取"+ m_status);
String str_get = m_orderId+m_ucid+m_amount+m_status+"gGoXQmgHA42egR";
String str_md5 = MD5(str_get);
if (m_status.equals("success")&&m_sign.equals(str_md5)) {
//支付成功
return true;
}else {
//支付失败
return false;
}
} catch (Exception e) {
// TODO: handle exception
return false;
}
}
private String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
//MD5校验
public String MD5(String text)
throws NoSuchAlgorithmException, Exception {
MessageDigest md;
md = MessageDigest.getInstance("MD5");
byte[] md5hash = new byte[32];
md.update(text.getBytes("iso-8859-1"), 0, text.length());
md5hash = md.digest();
return convertToHex(md5hash);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
flag = false;
}
@Override
public void unbindService(ServiceConnection conn) {
// TODO Auto-generated method stub
super.unbindService(conn);
}
}
MyDBHelper.java:数据库字段搭建
package com.example.blogforuc.uc;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDBHelper extends SQLiteOpenHelper{
private String sql_create = "create table orderinfo"+"(_id integer primary key autoincrement,orderid,flag)";
public MyDBHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL(sql_create);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
下边及支付界面: