易接SDK接入:Android手游支付功能接口实现,完整代码奉上

  之前在一家游戏公司写过游戏服务端,游戏支付功能,这个是接入“易接”平台的SDK实现的,

由于涉及的坑比较多,所以总结一下经验,以及奉上完整代码。


首先我们的项目是以Cocos2dx引擎的手游,这个用visual Studio编写代码,
这个项目是LUA工程,但是里面有多个平台的代码,但是我们现在只写Android这一块
它可以实现跨平台:Android,IOS,blackberry,Linux,marmalade,window平台上跑,


Lua工程代码可以像swift 的编译器那样,写完即刻运行,更新的时候,不需要重新下载一个包,
打补丁更新!维护起来很方便


由于我是写服务端,这一块,所以我简单陈述这个实现的过程,
首先网游肯定有充值的功能,我现在通过接入第三方的SDK 接口,实现这个支付的功能

易接SDK 帮助文档


https://www.1sdk.cn/helpcenter.html


一、首先我们需要精确的定位!


此操作编译软件:Eclipse_SDK
我们是一个网游,我们的项目是Android最终的目的是完成一个支付的功能
先选择客户端,只有客户端的接口完善了才会发送请求到服务端验证,才会同步信息!



既然选择了Android,我的代码无疑是JAVA 
为什么不选择C++呢?cocos2dx 不是C++吗?已经说了,这里是一个Android的项目



二、下载官方的参考文档 demo 和 sdk包


  http://www.1sdk.cn/download





这个是生成渠道包的软件,就是写好接口后,在通过其他平台接入扩展功能
游戏客户端 → 游戏服务端 → 易接服务端 → 其他渠道服务端


写好接口代码,找一个渠道服务端 注册申请开发者,

用 易接的PC端打包的APK,key在渠道服务端  这个获取,比如我注册“乐视/联想”的平台,然后上传app,可以获取key,打包后的apk,运行可以接入接口。 


三、我们打开下载的SDK包,
里面有很详细的内容,包括PDF文档,跟网页端的一样,只是稍微代码规范一点



资源包自己根据文档进行整理,该打上那些已经说的很详细了




demo有个易接的apk参考,文件夹里面是代码,
可以用ec导入,仔细查看


四、步骤流程:


我大体上的思路是:
1、在onCreate()创建窗口加载游戏的时候,初始化SDK ——initSDK();
并且写上登录监听
SFOnlineHelper.setLoginListener(activity, newSFOnlineLoginListener() {
@Override 
public void onLoginSuccess(SFOnlineUser user, Object customParams) { 
//登陆成功回调 

@Override 
public void onLoginFailed(String reason, Object customParams) { 
//登陆失败回调 

@Override 
public voidon Logout(Object customParams) { 
//登出回调 

});


2、在onStart()方法中,使用登录方法 SFOnlineHelper.login(activity, "Login");

监听到登录后,跳转登录验证
public void onLoginSuccess()


3、登录验证后,创建角色,验证角色
setRoleData(Context context, String roleId, String roleName, String roleLevel, String zoneId, String zoneName){
}


4、角色OK后,写支付的接口——定额计费,非定额计费
pay (Context context, intunitPrice, String unitName, int count, String callBackInfo, String callBackUrl,SFOnlinePayResultListenerpayResultListener){


}


5、扩展接口暂时不用写


注意:只有退出才清空内容 System.exit(0); ,


或许你打开原来的项目会说:
1.wtf,这不是继承Activity,不是FragmentActivity,而是
extends Cocos2dxActivity ?
2、wtf,这游戏项目没有xml页面?
3、退出按钮不听话了?游戏无法退出?无法监听按键?


这跟demo不一样啊!
该什么说呢?其实游戏页面只有一个activity,所有的页面都在这里显示


如果遇到闪退:1、登录验证失败,回退 2、代码报错 3、6.0的权限问题,降低为4.3 这样




五、完整代码公布:

1、LuaTest.java 主activity

(因为我只是一只菜鸟,所以狂打 log日志跟踪)

package com.android.zdhsoft;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import com.snowfish.cn.ganga.helper.SFOnlineExitListener;
import com.snowfish.cn.ganga.helper.SFOnlineHelper;
import com.snowfish.cn.ganga.helper.SFOnlineLoginListener;
import com.snowfish.cn.ganga.helper.SFOnlinePayResultListener;
import com.snowfish.cn.ganga.helper.SFOnlineUser;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.FrameLayout;
import android.widget.Toast;
import org.cocos2dx.lib.Cocos2dxActivity;
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
import org.json.JSONException;
import org.json.JSONObject;

import utils.LoginHelper;


public class luaTest extends Cocos2dxActivity {

	private static final String TAG = "--luaTest--";
	FrameLayout mViewContainer;
	String tag = null;
	static LoginHelper helper = null;

	
	protected void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "——————luaTest启动,onCreate——————");
		super.onCreate(savedInstanceState);
		
		//登录监听
		loginListener();
		Log.d(TAG, "——————启动登录监听,loginListener——————");
		
		// TODO 初始化易接sdk 不带初始化监听的接口
		SFOnlineHelper.onCreate(this);
		Log.d(TAG, "——————初始化SDK,onCreate——————");
	}
	
	public Cocos2dxGLSurfaceView onCreateGLSurfaceView() {
		return new Cocos2dxGLSurfaceView(this);
	}

	static {
		System.loadLibrary("cocos2dlua");
	}

	@Override
	public void onStart() {
		super.onStart();
		Log.d(TAG, "——————开始启动游戏——————");
		
		//这里 模拟一下 调用登录
		SFOnlineHelper.login(this, "Login"); 
		Log.d(TAG, "——————登录游戏,login——————");
	}

	@Override
	public void onPause() {
		super.onPause();
		Log.d(TAG, "——————暂停游戏——————");
		SFOnlineHelper.onPause(this);
		
		//除非退出游戏否则绝对不能调用  !!!!
//		System.exit(0);
	}

	public void onStop() {
		super.onStop();
		Log.d(TAG, "——————停止游戏——————");
		SFOnlineHelper.onStop(this);
	}

	@Override
	public void onResume() {
		super.onResume();
		Log.d(TAG, "——————重新开始游戏——————");
		SFOnlineHelper.onResume(this);
		
	}

	public void onDestroy() {
		super.onDestroy();
		Log.d(TAG, "——————销毁游戏——————");
		SFOnlineHelper.onDestroy(this);
	}

/*	protected void onRestart() {
		Log.d(TAG, "——————重新启动游戏——————");
		SFOnlineHelper.onRestart(this);
	}*/
	
	
	//登录的监听方法
	public void loginListener(){
		SFOnlineHelper.setLoginListener(this, new SFOnlineLoginListener(){

			@Override
			public void onLoginSuccess(SFOnlineUser user, Object customParams) {
				
				/**
				 * 获取用户信息 传到你们的游戏内,绑定游戏玩家  用户的唯一标示是  channneluserid
				 * 用户唯一标示  --- 该玩家在 该渠道 的唯一标示。若要实现全渠道 唯一 请自行处理映射关系 建议 使用 {sdk_userID}
				*/
				
				String userID = user.getChannelUserId();
				String app = user.getProductCode();
				String sdk = user.getChannelId();
				String token = user.getToken();
				String userName = user.getUserName(); // 这个参数是 可选的 不是用户唯一标示,通常建议不用。
				
				System.out.println("————"+"userID:"+userID+",app:"+app+",sdk:"+sdk +",token"+token+",userName:"+userName);
				
				
				// 用户信息获取结束
				//登录验证
				
				try {
					if(helper != null){
						helper.setOnlineUser(user);
					}
					LoginCheck(user);
					Toast.makeText(getContext(), "验证:账户登录成功", 3000).show();
					
				} catch (JSONException e) {
					e.printStackTrace();
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			}

			@Override
			public void onLoginFailed(String reason, Object customParams) {
				Log.d(TAG, "——————登录失败!——————");
				Toast.makeText(getContext(), "验证:账户登录失败", 3000).show();
			}

			@Override
			public void onLogout(Object customParams) {
				Log.d(TAG, "——————登出成功!——————");
				Toast.makeText(getContext(), "验证:登出成功", 3000).show();
			}

		});
	}
	
	//登出
	public void onlogout(Object customParams){
		Log.d(TAG, "——————登出游戏——————"+ customParams);
		SFOnlineHelper.logout(this, "LoginOut");
		
		Toast.makeText(this, "账户登出", Toast.LENGTH_LONG).show();
		/*if(helper!=null){
			helper.setOnlineUser(null);
			helper.setLogin(false);
			helper.getHandler(this).postDelayed(new Runnable(){

				@Override
				public void run() {
					SFOnlineHelper.login((Activity) getContext(), "Login"); 
					Log.d(TAG, "——————登出游戏,切换账号——————");
				}
				
			}, 200);
		}*/
	}

	
	//登录验证
	public void LoginCheck(final SFOnlineUser user) throws JSONException, UnsupportedEncodingException{
		Log.d(TAG, "——————登录验证!——————");
		//此处进行的登录验证是 模拟验证 
		// 正确的验证流程是    游戏客户端 ----》游戏服务器----》易接服务器---》渠道服务器
		// 这里就不做了 留个 空
		//TODO  实现真实的验证
		 
		
		String url = "http://192.168.0.105:8000/run"+createLoginURL(user);
		if (url == null)
			return;
		System.out.println("url:"+url);
		
		new Thread(new Runnable(){

			@Override
			public void run() {
				MainActivity.SendErrorToGMServer(user.getProductCode(), user.getChannelId(), user.getToken(), user.getChannelId());
				System.out.println("————1、发送登录验证到本地服务器————");
			}
			
		}).start();
		
		
		String result = LoginHelper.executeHttpGet(url);
		Log.e(TAG,"————发送信息成功————"+result);
		
		if(result==null ||!result.equals("SUCCESS")){
			if(helper != null){
				helper.setLogin(false);
			}
			LoginHelper.showMessage("未登录", this);
		}else{
			if(helper != null){
				helper.setLogin(true);
			}
		}
		
		// 通常在游戏内调用 上传角色信息的接口    这里模拟设置角色信息 
		setRole();

		// 这些做完就接好了 用户 系统  下面是支付  通常是用户触发
		pay();
		
		onBackPressed();
/*		Toast.makeText(getContext(), "退出!", 3000).show(); */
		
	}
	
	//模拟设置角色基本信息
	@SuppressWarnings("unused")
	private void setRole() throws JSONException{
	SFOnlineHelper.setRoleData(this, "1","骑士", "100", "1", "阿狸一区");
		
		Log.d(TAG, "——————角色初始化——————");
		
		// setData  key  --?  enterserver  levelup   createrole 最常见的三个场景。
		// info  用户信息  参考 demo的json  
		JSONObject  info = new JSONObject();
		 info.put("roleName", "saber");	//当前登录的玩家角色ID,必须为数字
		 info.put("roleId", "775522233"); //当前登录的玩家角色名,不能为空,不能为null
		 info.put("roleLevel", "100");	//当前登录的玩家角色等级,必须为数字,且不能为0,若无,传入1
		 info.put("zoneId", "1");		//当前登录的游戏区服ID,必须为数字,且不能为0,若无,传入1
		 info.put("zoneName", "阿狸一区");	//当前登录的游戏区服名称,不能为空,不能为null
		 info.put("balance", "0");		//用户游戏币余额,必须为数字,若无,传入0
		 info.put("vip", "1");			//当前用户VIP等级,必须为数字,若无,传入1
		 info.put("partyName", "无帮派");	//当前角色所属帮派,不能为空,不能为null,若无,传入“无帮派”
		 info.put("roleCTime", "234234");//单位为秒,创建角色的时间
		 info.put("roleLevelMTime", "54456556");//单位为秒,角色等级变化时间
		 
		 //实现完整角色验证
		SFOnlineHelper.setData(this, "key", info.toString()); //一定要 toString  !
		LoginHelper.showMessage("角色saber,登录验证成功!", this);
		Log.d(TAG, "——————角色验证成功!——————");
	}
	
	//传递地址	
	private String createLoginURL(SFOnlineUser user) throws UnsupportedEncodingException{
		StringBuilder builder = new StringBuilder();
		builder.append("?app=");
		builder.append(URLEncoder.encode(user.getProductCode(), "utf-8"));
		builder.append("&sdk=");
		builder.append(URLEncoder.encode(user.getChannelId(), "utf-8"));
		builder.append("&uin=");
		builder.append(URLEncoder.encode(user.getChannelUserId(), "utf-8"));
		builder.append("&sess=");
		builder.append(URLEncoder.encode(user.getToken(), "utf-8"));
		return builder.toString();
	}
	

	// 退出
	@Override
	public void onBackPressed() {
		Log.d(tag, "————onBackPressed,退出游戏————");
		// exit方法用于系统全局退出
		SFOnlineHelper.exit(this, new SFOnlineExitListener() {
			@Override
			public void onSDKExit(boolean bool) {
				if (bool) {
					// apk退出函数,demo中也有使用System.exit()方法;但请注意360SDK的退出使用exit()会导致游戏退出异常
					finish();
				}
			}

			/*
			 * onNoExiterProvide
			 * 
			 * @description SDK没有退出方法及界面,回调该函数,可在此使用游戏退出界面
			 */
			@Override
			public void onNoExiterProvide() {
				AlertDialog.Builder builder = new Builder(luaTest.this);
				builder.setTitle("是否要退出游戏界面");
				builder.setPositiveButton("退出",
						new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								luaTest.this.finish();
								System.exit(0);
							}
						});
				builder.show();
			}
		});
	}
	
	//定额计费接口
	@SuppressWarnings("unused")
	private void pay(){
		int unitPrice = 10 ;  	//游戏道具价格,单位为 分
		String itemName="钻石";  //虚拟货币名称
		int count= 1; 		//默认道具数量
		String callBackInfo="12345678910"; //自定义的说明,判断交易详细内容,不要用空格和特殊字符; 暂时设定为订单ID
		String callBackUrl = "http://123.57.12.130:8000/paycallback" ; 		// arg5 ,将交易结果传给服务器的通知url,可看到explain的信息
		// arg6透传参数 不要有汉字空格,可自定义
		
		try{
		SFOnlineHelper.pay(this, unitPrice, itemName, count, callBackInfo,callBackUrl, new SFOnlinePayResultListener() {
			@Override
			public void onSuccess(String remain) {

				Toast.makeText(getContext(), "支付成功,获得1钻石", 2000).show();
				Log.d(TAG,"—————支付成功———————");
				
			}
			
			@Override
			public void onFailed(String remain) {
				// 支付失败
				Log.d(TAG,"—————支付失败———————");
				Toast.makeText(getContext(), "错误信息,支付失败!", 2000).show();
			}
			
			@Override
			public void onOderNo(String orderNo) {
				// 订单创建成就会回调通常记录到服务器 
				Log.e(TAG, "————订单创建,发生到服务器");
				LoginHelper.showMessage("购买钻石订单号:" + orderNo, getContext());
			}
			
		});
		
		}catch(Exception e){
			e.printStackTrace();
			Log.e(TAG, "————错误,没有进入支付!————");
		}
		
	}
	
	
	//非定额计费接口
	@SuppressWarnings("unused")
	private void charge(int price){
		if(!LoginHelper.instance().isLogin()){
			
			Toast.makeText(this,"用户未登陆",Toast.LENGTH_SHORT).show();
			return ;
		}
		Log.e(TAG, "—————非定额计费—————");
		
		String itemName="钻石";  		//虚拟货币名称
		int unitPrice = 10 ;  	//游戏道具价格,单位为 分 
		int count= 1; 		//默认道具数量
		String callBackInfo="123456"; //自定义的说明,判断交易详细内容,不要用空格和特殊字符,暂时设置为订单ID
		String callBackUrl = "http://123.57.12.130:8000/paycallback" ; 	 // arg5 ,将交易结果传给服务器的通知url,可看到explain的信息
									// arg6透传参数 不要有汉字空格,可自定义
		
		try{
			SFOnlineHelper.charge(this,itemName,unitPrice, count,callBackInfo, callBackUrl, new SFOnlinePayResultListener() {

				@Override
				public void onSuccess(String remain) {
					Toast.makeText(getContext(), "支付成功,获得10钻石,5黄金,20积分", 2000).show();
					System.out.println("—————支付成功———————");
				}
		
				@Override
				public void onFailed(String remain) {
					// 支付失败
					Toast.makeText(getContext(), "错误信息,支付失败!", 2000).show();
				}

				@Override
				public void onOderNo(String orderNo) {
					LoginHelper.showMessage("订单号:" + orderNo, getContext());
				}

			});
		}catch(Exception e){
			e.printStackTrace();
			Log.e(TAG, "————错误,没有进入定额支付!————");
		}

	}	
}


class LuaGLSurfaceView extends Cocos2dxGLSurfaceView {

	public LuaGLSurfaceView(Context context) {
		super(context);
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {

		if (keyCode == KeyEvent.KEYCODE_BACK) {
			android.os.Process.killProcess(android.os.Process.myPid());
		}
		return super.onKeyDown(keyCode, event);
	}

}

2、客户端(当前ec—sdk项目)请求发送/接收 服务端消息 activity 

MainActivity :

package com.android.zdhsoft;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import com.android.zdhsoft.R;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

public class MainActivity extends Activity {

	private static final String TAG ="--MainActivity--";
	private static  String GMSERVER_API = "http://192.168.0.105:8000/run";  //公司外网地址,这个请自己填写
	
	 Messenger mes;
	 boolean isBound;
	    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Log.d(TAG, "—————onCreate—————");
		
	}
	
	
//登录发生请求	  
    public void doLogin(View view) {  
        Intent intent = new Intent(MainActivity.this, luaTest.class);  
        startActivity(intent);  
		Log.d(TAG, "—————doLogin—————");
    }  
	
    protected void onStart(){
    	super.onStart(); 
    }
    
	@Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG,"—————onStop—————");
    }
	

	public static void setErrorCollectApi(String api){
		GMSERVER_API = api;
	}
	
//多抛出异常
	public static void SendErrorToGMServer(String app,String sdk,String token,String userName){
		Log.d(TAG, "—————SendErrorToGMServer—————");
			List<NameValuePair> params = new ArrayList<NameValuePair>();

			try {
				HttpPost post = new HttpPost(GMSERVER_API);
				params.add(new BasicNameValuePair("app",app));
				params.add(new BasicNameValuePair("sdk",sdk));
				params.add(new BasicNameValuePair("token",token));
				params.add(new BasicNameValuePair("userName",userName));
				
/*				params.add(new BasicNameValuePair("sys_version",android.os.Build.VERSION.RELEASE));*/
				params.add(new BasicNameValuePair("dev",android.os.Build.MODEL));
				post.setEntity(new UrlEncodedFormEntity(params));
				new DefaultHttpClient().execute(post);
				System.out.println("—————异常一—————");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
				Log.d(TAG, "—————异常一—————");
			} catch (ClientProtocolException e) {
				e.printStackTrace();
				Log.d(TAG, "—————异常二—————");
			} catch (IOException e) {
				e.printStackTrace();
				Log.d(TAG, "—————异常三—————");
			}
			
			Log.d(TAG, "—————SendErrorToGMServer完成—————");
	}
	
}

3、AndroidManifest.xml 

(仅供参考)

<?xml version="1.0" encoding="UTF-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.zdhsoft"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="20" />

//权限
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <uses-feature android:glEsVersion="0x00020000" />
-
    <application
        android:name="com.snowfish.cn.ganga.helper.SFOnlineApplication"
        android:allowBackup="true"
        android:icon="@drawable/aa"
        android:label="@string/app_name" >
-//屏幕控制
        <activity
            android:name="activity.DemoMainActivity"
            android:configChanges="orientation|keyboardHidden|navigation|screenSize"
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:screenOrientation="sensor"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >

            <!-- <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> -->

        </activity>
-
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >

            <!-- <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> -->

        </activity>

        <!-- android:screenOrientation="" landscape:横屏;portrait:竖屏;sensor:物理感应器 -->

-
        <activity
            android:name=".luaTest"
            android:configChanges="orientation|keyboardHidden|navigation|screenSize"
            android:label="@string/title_activity_main"
            android:screenOrientation="sensor"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
-
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name="view.PaymentView"
            android:label="@string/title_activity_payment" >
        </activity>
-
        <service
            android:name="com.snowfish.a.a.s.ABGSvc"
            android:enabled="true"
            android:process="com.snowfish.a.a.bg" >
-
            <intent-filter>
                <action android:name="com.snowfish.a.a.s.ABGSvc" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </service>

        <meta-data
            android:name="com.snowfish.customer"
            android:value="SNOWFISH" >
        </meta-data>
        <meta-data
            android:name="com.snowfish.channel"
            android:value="SNOWFISH" >
        </meta-data>
        <meta-data
            android:name="com.snowfish.sdk.version"
            android:value="2" >
        </meta-data>

        <!-- END SNOWFISH SDK -->


        <!-- 此参数不做修改,保持默认就行,打包会自动替换 -->


        <!-- com.snowfish.appid 游戏的唯一标识,用于区分不同游戏的唯一标准。在易接开发者中心游戏管理模块中创建新游戏获取 -->

        <meta-data
            android:name="com.snowfish.appid"
            android:value="{4477D4AB-399F0338}" >
        </meta-data>

        <!-- com.snowfish.channelid 支付渠道标识,此id可区分渠道,在易接后台有相应的渠道对照表 -->

        <meta-data
            android:name="com.snowfish.channelid"
            android:value="{4ff036a1-3254eafe}" >
        </meta-data>
    </application>

    <supports-screens
        android:anyDensity="true"
        android:largeScreens="true"
        android:normalScreens="true"
        android:smallScreens="true" />

</manifest>

其他修改请参考帮助文档!


六、服务端代码公布:

Eclipse,这个是另外一个ec,不是ec_sdk

1、BaseServlet.java

package com.test;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public  class BaseServlet extends HttpServlet{
	
	// 应用在易接服务获取的同步密钥
	private final String PRIVATE_KEY = "V2X0XE5DSZ4AGFXJCA5YZ5CDUQO4LPJY";  //自己在轨道SDK申请,我这个是乐视的
	private final int LOGIN_RESULT_SUCCESS = 0;
	private final String CHECK_LOGIN_URL = "http://sync.1sdk.cn/login/check.html";

	private static final long serialVersionUID = 1L;
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		System.out.println("BaseServlet.doGet()");
		 doPost(req, resp);  
	}

	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println("BaseServlet.doPost()");
		
		PrintWriter w = resp.getWriter();
		String app = req.getParameter("app");
		String sdk = req.getParameter("sdk");
		String uin = req.getParameter("token");
		String sess = req.getParameter("userName");
		
		StringBuilder getUrl = new StringBuilder();
		getUrl.append(CHECK_LOGIN_URL);
		getUrl.append("?app=");
		getUrl.append(app);
		getUrl.append("&sdk=");
		getUrl.append(sdk);
		getUrl.append("&uin=");
		getUrl.append(URLEncoder.encode(uin, "UTF-8"));
		getUrl.append("&sess=");
		getUrl.append(URLEncoder.encode(sess, "UTF-8"));
		
		try {
			ServerLauncher.SimpleHTTPResult ret = ServerLauncher.simpleInvoke ("GET", getUrl.toString(), null, null);
			// 下面的返回值由CP服务器和客户端定义,这里的返回值只做参考用
			if (ret.code != 200) {
				w.write("ERROR");
				return;
			}
			if (ret.data == null || ret.data.length == 0) {
				w.write("ERROR");
				return;
			} else {
				String r = new String (ret.data);
				Integer i = new Integer(r);
				if (i == LOGIN_RESULT_SUCCESS) {
					w.write("SUCCESS");
					System.out.println("app:"+app);
					System.out.println("sdk:"+sdk);
					System.out.println("token:"+uin);
					System.out.println("userName:"+sess);
					System.out.println("————登录验证完成————");
				} else {
					w.write("ERROR");
					System.out.println("————登录验证失败!————");
				}
				return;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			w.flush();
			w.close();
		}
		
/*
 * 以上登录验证流程完成!
 * 以下是订单支付的接收信息		
 */
		
		String app2 = req.getParameter("app2");
		String cbi = req.getParameter("cbi");
		String ct = req.getParameter("ct");
		String fee = req.getParameter("fee");
		String pt = req.getParameter("pt");
		
		String ssid = req.getParameter("ssid");
		String st = req.getParameter("st");
		String tcd = req.getParameter("tcd");
		String uid = req.getParameter("uid");
		String ver = req.getParameter("ver");
		
		
		StringBuffer sbEnc = new StringBuffer (); 
		sbEnc.append ("app="); 
		sbEnc.append (req.getParameter("app"));
		sbEnc.append ("&cbi="); 
		sbEnc.append (req.getParameter("cbi")); 
		sbEnc.append ("&ct="); 
		sbEnc.append (req.getParameter("ct")); 
		sbEnc.append ("&fee="); 
		sbEnc.append (req.getParameter("fee"));  
		sbEnc.append ("&pt="); 
		sbEnc.append (req.getParameter("pt"));
		sbEnc.append ("&sdk="); 
		sbEnc.append (req.getParameter("sdk"));
		sbEnc.append ("&ssid="); 
		sbEnc.append (req.getParameter("ssid")); 
		sbEnc.append ("&st=");
		sbEnc.append (req.getParameter("st")); 
		sbEnc.append ("&tcd="); 
		sbEnc.append (req.getParameter("tcd"));
		sbEnc.append ("&uid="); 
		sbEnc.append (req.getParameter("uid")); 
		sbEnc.append ("&ver="); 
		sbEnc.append (req.getParameter("ver")); 
		
		String sign = req.getParameter("sign");
		boolean result = MD5.encode(sbEnc + PRIVATE_KEY).equalsIgnoreCase(sign);
		
		if(result){
			// 此处CP可以持久化消费记录
			//st==1是支付成功,才能给用户发道具

			// 操作成功后需要返回SUCCESS告诉易接服务器已经接收成功
			w.write("SUCCESS");
			System.out.println("开始验证订单!");
			System.out.println("生成的订单信息:"+cbi+ct+fee+pt+ssid+st+tcd+uid+ver);
			
		}else{
			// 返回ERROR易接服务器会根据一定的策略重新同步消费记录给CP
			w.write("ERROR");
			System.out.println("开始验证订单失败!");
		}
		w.flush();
		w.close();
	}
	
	
}

2、ServerLauncher.java

package com.test;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.nio.SelectChannelConnector;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.mortbay.thread.BoundedThreadPool;

public class ServerLauncher {


	private void launch(int port) throws Exception {
		Server server = new Server();
		BoundedThreadPool threadPool = new BoundedThreadPool();
		threadPool.setMinThreads(50);
		threadPool.setMaxThreads(1000);
		server.setThreadPool(threadPool);
		SelectChannelConnector connector = new SelectChannelConnector();
		connector.setPort(port);
//		server.addHandler(webContext);
		server.addConnector(connector);
		Context root = new Context(server, "/", 1);
		
		root.addServlet(new ServletHolder(new BaseServlet()),"/run");
		
		server.start();
	}


	public static void main(String[] args) throws Exception {
		new ServerLauncher().launch(8000);
		System.out.println("Start ");
	}

	//易接例子
	
	public static class SimpleHTTPResult {
		public int code;
		public byte[] data;
	}
	
	public static SimpleHTTPResult simpleInvoke (String method, String url, String contentType, byte[] outdata) throws IOException {
		SimpleHTTPResult res = new SimpleHTTPResult ();
		HttpURLConnection http = (HttpURLConnection)(new URL (url)).openConnection ();
		http.setRequestMethod (method);
		if (contentType != null)
			http.setRequestProperty ("Content-Type", contentType);
		if (outdata != null) {
			http.setRequestProperty ("Content-Length", Integer.toString (outdata.length));
		}
		http.setDoOutput (outdata != null ? true : false);
		http.setDoInput (true);
		http.connect ();
		if (outdata != null) {
			OutputStream outs = http.getOutputStream ();
			outs.write (outdata);
			outs.close ();
		}
		res.code = http.getResponseCode ();
		if (res.code == 404) {
			return res;
		}
		InputStream stream = http.getInputStream ();
		try {
			int len = http.getContentLength ();
			byte[] data;
			if (len >= 0) {
				data = new byte[len];
				int off = 0;
				while (off < len) {
					int read = stream.read (data, off, len - off);
					if (read < 0)
						throw new IOException ();
					off += read;
				}
			} else {
				ByteArrayOutputStream baos = new ByteArrayOutputStream ();
				byte[] buffer = new byte[4096];
				for (;;) {
					int read = stream.read (buffer, 0, buffer.length);
					if (read < 0)
						break;
					baos.write (buffer, 0, read);
				}
				baos.close ();
				data = baos.toByteArray ();
			}
			res.data = data;
		} finally {
			stream.close ();
		}
		return res;
	}
	
	public static byte[] post (URL url, String contentType, byte[] outdata) throws IOException {
		HttpURLConnection http = (HttpURLConnection)url.openConnection ();
		http.setRequestProperty ("Content-Type", contentType);
		http.setDoOutput (true);
		http.setDoInput (true);
		http.connect ();
		OutputStream outs = http.getOutputStream ();
		outs.write (outdata);
		outs.close ();
		int code = http.getResponseCode ();
		if (code != 200) {
			throw new IOException ("Bad RPC '" + url.toString () + "': " + code);
		}
		InputStream stream = http.getInputStream ();
		try {
			int len = http.getContentLength ();
			byte[] data;
			if (len >= 0) {
				data = new byte[len];
				int off = 0;
				while (off < len) {
					int read = stream.read (data, off, len - off);
					if (read < 0)
						throw new IOException ();
					off += read;
				}
			} else {
				ByteArrayOutputStream baos = new ByteArrayOutputStream ();
				byte[] buffer = new byte[4096];
				for (;;) {
					int read = stream.read (buffer, 0, buffer.length);
					if (read < 0)
						break;
					baos.write (buffer, 0, read);
				}
				baos.close ();
				data = baos.toByteArray ();
			}
			return data;
		} finally {
			stream.close ();
		}
	}
	
}

3、MD5.java 这个加密用的


package com.test;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MD5 {
    
    // 全局数组
    private final static String[] strDigits = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

    public MD5() {
    }

    // 返回形式为数字跟字符串
    private static String byteToArrayString(byte bByte) {
        int iRet = bByte;
        // System.out.println("iRet="+iRet);
        if (iRet < 0) {
            iRet += 256;
        }
        int iD1 = iRet / 16;
        int iD2 = iRet % 16;
        return strDigits[iD1] + strDigits[iD2];
    }

    // 返回形式只为数字
    private static String byteToNum(byte bByte) {
        int iRet = bByte;
        System.out.println("iRet1=" + iRet);
        if (iRet < 0) {
            iRet += 256;
        }
        return String.valueOf(iRet);
    }

    // 转换字节数组为16进制字串
    private static String byteToString(byte[] bByte) {
        StringBuffer sBuffer = new StringBuffer();
        for (int i = 0; i < bByte.length; i++) {
            sBuffer.append(byteToArrayString(bByte[i]));
        }
        return sBuffer.toString();
    }

    public static String encode(String strObj) {
        String resultString = null;
        try {
            resultString = new String(strObj);
            MessageDigest md = MessageDigest.getInstance("MD5");
            // md.digest() 该函数返回值为存放哈希值结果的byte数组
            resultString = byteToString(md.digest(strObj.getBytes()));
        } catch (NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
        return resultString;
    }

    public static void main(String[] args) {
        System.out.println(MD5.encode("000000"));
    }
}












猜你喜欢

转载自blog.csdn.net/ssh159/article/details/78118611
今日推荐