美文网首页unity
Android微信支付宝QQ支付接入详解-Unity3D原生支付

Android微信支付宝QQ支付接入详解-Unity3D原生支付

作者: Camming | 来源:发表于2019-05-18 17:10 被阅读48次

    一、微信支付
    第一步登录微信开放平台:https://open.weixin.qq.com/,进入账号中心进行开发者资质认证,需要填写公司资料,包括但不限于,公司注册号,公司营业执照,公司对外办公电话,公司 对公银行卡信息(卡号,发卡行)。审核时间为
    一周左右,进行开发者资质认证需要支付 300 元人民币/年,只有具备开发者资质认证的开发者才能够使用 app 支付,授权登录等接口。
    申请 APP_ID/APP_KEY
    每个应用/游戏要调用微信的接口都需要有一个微信标志,这个唯一标志通常成为 APP_ID 或者 APP_KEY,各开放平台差异不大进入管理中心,创建移动应用,每个开发者具有 10 个应用的创建机会,好在创建的应用可以随时删除。 已上线的应用就不建议手贱删除!!申请 appid 需要填写应用信息:应用名称,包名,签名(keystore 的 md5 值去分号小写),icon(2828 & 108108),app 下载地址等信息,即可分配到一个 appid。

    开通微信商户平台,登录微信商户平台https://pay.weixin.qq.com,这里也是需要300元人民币/年开通微信支付功能,绑定企业银行,开通企业微信商户,在产品中心中,开通“APP支付”功能

    微信截图_20190518163505.png
    开通成功之后绑定微信开放平台的APPID
    微信截图_20190518163723.png

    在产品中心中,左边列表选择“APPID授权管理”进行绑定,


    微信截图_20190518163835.png
    微信截图_20190518163850.png

    此时,微信支付申请就搞定了,可以进行开发了
    Android studio 新建工程
    在build.gradle 中的dependencies 中
    compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
    依赖微信支付,登录的依赖包

    在工程的目录包名下新建目录wxapi,新建WXPayEntryActivity.java类,此类名称不可以变,必须放在wxapi下,如包名为com.xx.xxx.xxx,WXPayEntryActivity类就放在com.xx.xxx.xxx.wxapi下,
    在AndroidManifest.xml中配置
    <activity
    android:name="工程包名.WXPayEntryActivity"
    android:exported="true"
    android:launchMode="singleTop"/>
    及网络权限
    <uses-permission android:name="android.permission.INTERNET" />

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(WeiXinPay.getInstance(this)!=null){
            WeiXinPay.getInstance(this).getWXApi().handleIntent(getIntent(), this);
        }else {
            finish();
        }
    }
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        if (!WeiXinPay.getInstance(this).getWXApi().handleIntent(intent, this)) {
            finish();
        }
    }
    @Override
    public void onReq(BaseReq baseReq) {
    
    }
    
    @Override
    public void onResp(BaseResp baseResp) {
        //4、支付结果回调 https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5
    
        Log.e("WXPayEntryActivity", "baseResp=" + baseResp.toString());
        if(baseResp.getType() == ConstantsAPI.COMMAND_PAY_BY_WX) {
            Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
            if(WeiXinPay.getInstance(this) != null) {
                if(baseResp.errStr != null) {
                    Log.e("WXPayEntryActivity", "errStr=" + baseResp.errStr);
                }
                WeiXinPay.getInstance(this).onResp(baseResp);
                finish();
            }
        }
    }
    

    }
    回调中 errCode 值列表:
    0 支付成功
    -1 发生错误 可能的原因:签名错误、未注册 APPID、项目设
    置 APPID 不正确、注册的 APPID 与设置的不匹配、其他异常
    等。
    -2 用户取消 发生场景:用户不支付了,点击取消,返回 APP。

    微信支付的回调再该类的onResp方法中回调
    微信支付类,通过服务器返回的数据,拿到appid,注册到微信 mIWXAPI.registerApp(appId);
    其中服务端返回的数据中partnerid 就是商户id
    根据服务端返回的数据拉起支付
    PayReq req = new PayReq();
    req.appId = payBean.getAppid();
    req.partnerId = payBean.getMch_id();
    req.prepayId = payBean.getPrepay_id();
    req.nonceStr = payBean.getNonce_str();
    req.timeStamp = payBean.getTimestamp();
    req.packageValue = "Sign=WXPay";
    req.sign = payBean.getSignB();//服务端的签名 正式使用
    //req.sign = genAppSign(payBean).toUpperCase();//客户端的签名 测试
    mIWXAPI.sendReq(req);

    需要注意的是,在微信开放平台创建的应用,填写的包名和签名,必须和工程保持一致,否则拉起支付有可能返回-1,

    package 是不变的,sign 是服务签名的,客户端测试的话,可以放在客户端签名
    测试代码
    orderWechat = "{\n" +
    " "appid": "wxca3042x2xxxxx4e344cf01",\n" +
    " "partnerid": "1526501",\n" +
    " "prepayid": "wx161841xxxxxxx542151",\n" +
    " "timestamp": "1558xxx003316",\n" +
    " "noncestr": "c8J2CxxnDxx7qDx15dus",\n" +
    " "package": "Sign=WXPay",\n" +
    " "sign": "34CBBAxxxxxxx0F59775F"\n" +
    "}";
    if(TextUtils.isEmpty(orderWechat)){
    Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
    return;
    }
    //微信支付
    // * 注意
    // * 微信的APPID 和签名信息及报名和微信开放平台填写的要一致
    pay.payDoraVip(MainActivity.this,"PHP",JPay.PayMode.WXPAY,orderWechat);

    客户端签名样例,key值按升序拼接在用MD5加密
    private String genAppSign(WechatPayBean payBean) {

        List<NameValuePair> signParams = new LinkedList<>();
        signParams.add(new NameValuePair("appid", payBean.getAppid()));
        signParams.add(new NameValuePair("noncestr", payBean.getNonce_str()));
        signParams.add(new NameValuePair("package", "Sign=WXPay"));
        signParams.add(new NameValuePair("partnerid",payBean.getMch_id()));
        signParams.add(new NameValuePair("prepayid", payBean.getPrepay_id()));
        signParams.add(new NameValuePair("timestamp", payBean.getTimestamp()));
    
        StringBuilder sb = new StringBuilder();
    
        for (int i = 0; i < signParams.size(); i++) {
            sb.append(signParams.get(i).getName());
            sb.append('=');
            sb.append(signParams.get(i).getValue());
            sb.append('&');
        }
        sb.append("key=");
        sb.append("api密钥");
        String appSign = MD5Utils.getMessageDigest(sb.toString().getBytes());
        return appSign;
    }
    

    二、支付宝支付
    登录支付宝网站https://auth.alipay.com
    进行企业验证,验证完成进入我的开放平台

    我的开放平台---开发中心--网页移动应用
    立即创建应用,创建完成添加APP支付功能
    在工程到导入alipaySdk-20180601.jar包,

    /**

    • Created by camming on 2019/11/21.
    • 支付宝支付
      */
    private static Alipay mAliPay;
    private Activity mContext;
    private JPay.JPayListener mJPayListener;
    
    //支付失败
    public static final int PAY_ERROR = 0x001;
    //支付网络连接出错
    public static final int PAY_NETWORK_ERROR = 0x002;
    //支付结果解析错误
    public static final int RESULT_ERROR = 0x003;
    //正在处理中
    public static final int PAY_DEALING = 0x004;
    //其它支付错误
    public static final int PAY_OTHER_ERROR = 0x006;
    //支付参数异常
    public static final int PAY_PARAMETERS_ERROE = 0x007;
    
    
    private Alipay(Activity context) {
        mContext = context;
    }
    
    public static Alipay getInstance(Activity context){
        if (mAliPay == null) {
            synchronized(WeiXinPay.class){
                if (mAliPay == null) {
                    mAliPay = new Alipay(context);
                }
            }
        }
        return mAliPay;
    }
    
    
    public void startAliPay(final String orderInfo,JPay.JPayListener listener){
       boolean bool =  checkAliPayInstalled(mContext);
       if(!bool){
           Toast.makeText(mContext,"支付宝未安装!",Toast.LENGTH_SHORT).show();
           return;
    
       }
        mJPayListener = listener;
        Runnable payRunnable = new Runnable() {
            @Override
            public void run() {
                PayTask alipay = new PayTask(mContext);
                Map<String, String> result = alipay.payV2(orderInfo, true);
                Message msg = new Message();
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        };
        Thread payThread = new Thread(payRunnable);
        payThread.start();
    }
    /**
     * 检测是否安装支付宝
     * @param context
     * @return
     */
    public static boolean checkAliPayInstalled(Context context) {
    
        Uri uri = Uri.parse("alipays://platformapi/startApp");
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        ComponentName componentName = intent.resolveActivity(context.getPackageManager());
        return componentName != null;
    }
    
    
    private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @SuppressWarnings("unchecked")
        public void handleMessage(Message msg) {
            PayResult payResult = new PayResult((Map<String, String>) msg.obj);
    
            Log.e("payResult= ",payResult.toString());
            System.out.print("payResult= "+payResult.toString());
    
            String resultStatus = payResult.getResultStatus();
            if (mJPayListener ==null){
                return;
            }
            // https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.xN1NnL&treeId=204&articleId=105302&docType=1
            if(payResult == null) {
                mJPayListener.onPayError(RESULT_ERROR,"结果解析错误");
                return;
            }
            if(TextUtils.equals(resultStatus, "9000")) {
                //支付成功
                mJPayListener.onPaySuccess();
            } else if(TextUtils.equals(resultStatus, "8000")) {
                //正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
                mJPayListener.onPayError(PAY_DEALING,"正在处理结果中");
            } else if(TextUtils.equals(resultStatus, "6001")) {
                //支付取消
                mJPayListener.onPayCancel();
            } else if(TextUtils.equals(resultStatus, "6002")) {
                //网络连接出错
                mJPayListener.onPayError(PAY_NETWORK_ERROR,"网络连接出错");
            } else if(TextUtils.equals(resultStatus, "4000")) {
                //支付错误
                mJPayListener.onPayError(PAY_ERROR,"订单支付失败");
            }else {
                mJPayListener.onPayError(PAY_OTHER_ERROR,resultStatus);
            }
        }
    };
    

    }

    /**

    • create by camming 2019/02/14
    • 情人节也要写代码
    • 支付宝支付
    • */
    public AliPayTask(Activity context) {
        this.mContext = context;
    }
    
    public AliPayTask(Activity context,String type,JPay.JPayListener listener) {
        this.mContext = context;
        this.mJPayListener =listener;
        this.serverType = type;
    }
    
    
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    
    
    @Override
    protected void onPostExecute(String result) {
        Log.e("AideaAliPayTask", "result"+result);
    //  AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
        try {
            if (result!=null){
            //  AlipayBean resultBean = JSONObject.parseObject(result,new TypeReference<AlipayBean>(){});
                if(serverType.equals(API_TYPE_PHP)){
                    System.out.println("PHP后台返回的数据orderInfo="+result);
                    PayUtils.getIntance(mContext).startAliPay(result,mJPayListener);
                }else{
                    JSONObject jsonObject=new JSONObject(result);
                    int code  = jsonObject.getInt("code");
                    if(code==0){
                        String resultData = jsonObject.getString("data");
                        System.out.println("orderInfo="+resultData);
                        ///Toast.makeText(mContext, "正在调起支付", Toast.LENGTH_SHORT).show();
                        PayUtils.getIntance(mContext).startAliPay(resultData,mJPayListener);
                    }else{
                        Toast.makeText(mContext, "错误"+jsonObject.getString("message"), Toast.LENGTH_SHORT).show();
                    }
    
                }
    
            }else {
    
                System.out.println("get  AliPay exception, is null");
            }
        } catch (Exception e) {
            Log.e("PAY_GET", "异常:"+e.getMessage());
            Toast.makeText(mContext, "异常:"+e.getMessage(), Toast.LENGTH_SHORT).show();
        }
        super.onPostExecute(result);
    }
    

    }

    三、QQ支付
    登录网站https://qpay.qq.com/
    申请APP支付,创建应用

    image.png
    image.png

    在工程项目目录下的wxapi目录下,新建一个QQ支付回调的类,我这里是QQCallbackActivity.java
    /**

    • Create by camming 2019/02/20
    • qq支付通知
    • */
    String appId = "101538445";
    IOpenApi openApi;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       // setContentView(R.layout.activity_callback);
    
        openApi = OpenApiFactory.getInstance(this, appId);
        openApi.handleIntent(getIntent(), this);
    }
    
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        setIntent(intent);
        openApi.handleIntent(intent, this);
    }
    
    
    @Override
    public void onOpenResponse(BaseResponse response) {
        String title = "Callback from mqq";
        String message;
        QQPay.getInstance(this).onQQResponse(response);
        if (response == null) {
            message = "response is null.";
            return;
        } else {
            if (response instanceof PayResponse) {
                PayResponse payResponse = (PayResponse) response;
    
                message = " apiName:" + payResponse.apiName
                        + " serialnumber:" + payResponse.serialNumber
                        + " isSucess:" + payResponse.isSuccess()
                        + " retCode:" + payResponse.retCode
                        + " retMsg:" + payResponse.retMsg;
                if (payResponse.isSuccess()) {
                    if (!payResponse.isPayByWeChat()) {
                        message += " transactionId:" + payResponse.transactionId
                                + " payTime:" + payResponse.payTime
                                + " callbackUrl:" + payResponse.callbackUrl
                                + " totalFee:" + payResponse.totalFee
                                + " spData:" + payResponse.spData;
                    }
                    
                }
            } else {
                message = "response is not PayResponse.";
            }
        }
        
    }
    

    }

    在AndroidManifest.xml中配置
    <activity
    android:name="工程包名.wxapi.QQCallbackActivity"
    android:launchMode="singleTop"
    android:exported="true" >
    <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.BROWSABLE"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:scheme="qwallet+qq商户id"/>
    </intent-filter>
    </activity>

    导入mqqopenpay.jar,

    /**

    • Created by camming on 2019\2\19 0019.
    • code is data data is code
    • qq支付
      */
    private static final String TAG = "QQPay";
    @SuppressLint("StaticFieldLeak")
    private static QQPay mQQPay;
    private Context mContext;
    private String callbackScheme = "qwallet+qqid";
    private IOpenApi openApi;
    
    int paySerial = 1;
    
    public static final String QQ_APP_ID = "qqid";
    // 签名步骤建议不要在app上执行,要放在服务器上执行
    public static final String APP_KEY = "商户key";
    
    private JPay.JPayListener mJPayListener;
    
    public static QQPay getInstance(Context context){
        if (mQQPay == null) {
            synchronized(QQPay.class){
                if (mQQPay == null) {
                    mQQPay = new QQPay(context);
                }
            }
        }
        return mQQPay;
    }
    private QQPay(Context context) {
        mContext = context;
        if(openApi==null)
            openApi = OpenApiFactory.getInstance(mContext, QQ_APP_ID);
    }
    
    /**手机QQ是否已经安装*/
    public boolean isMqqInstalled() {
        if(openApi==null)
            return false;
        else
            return openApi.isMobileQQInstalled();
    }
    /**是否支持手机qq支付*/
    public boolean isMqqSupportPay() {
        if(openApi==null)
            return false;
        else
            return openApi.isMobileQQSupportApi(OpenConstants.API_NAME_PAY);
    }
    

    // public void startQQPay(String payResult, JPay.JPayListener listener){

    // startQQPay(resultBean,listener);
    // }
    /**
    * 开始QQ支付
    *
    * */
    public void startQQPay(String pay, JPay.JPayListener listener){
    this.mJPayListener = listener;

        QQPayBean payBean = JSONObject.parseObject(pay,new TypeReference<QQPayBean>(){});
        Log.i("qqpay","payBean="+payBean);
    

    // ToastUtils.show(mContext,payBean);
    if(!isMqqInstalled()){
    Toast.makeText(mContext,"QQ未安装!",Toast.LENGTH_SHORT).show();
    return;
    }
    if(!isMqqSupportPay()){
    Toast.makeText(mContext,"该QQ版本不支持QQ支付!",Toast.LENGTH_SHORT).show();
    return;
    }
    PayApi api = new PayApi();
    api.appId = payBean.getAppid();
    api.serialNumber = "" + paySerial++;//支付序号
    api.callbackScheme = callbackScheme;
    api.tokenId = payBean.getPrepay_id();// QQ钱包支付生成的token_id
    api.pubAcc = "";
    api.pubAccHint = "";
    api.nonce = payBean.getNonce_str();
    api.timeStamp = System.currentTimeMillis() / 1000;
    api.bargainorId = payBean.getMch_id();

        //直接使用后台返回的签名数据  如果使用服务端的签名,把
        //下面的signApi()方法注释掉
    

    // api.sig = "";
    // api.sigType = "HMAC-SHA1";

        try {
            //为了测试,这里直接签名,此步骤放在服务端
            signApi(api);
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(mContext,"签名异常!",Toast.LENGTH_SHORT).show();
            return;
        }
    
        if (api.checkParams()) {
            openApi.execApi(api);
        }else{
            Toast.makeText(mContext,"支付参数有误!",Toast.LENGTH_SHORT).show();
        }
    
    }
    
    /**
     * 签名步骤建议不要在app上执行,要放在服务器上执行.
     */
    public void signApi(PayApi api) throws Exception {
        // 按key排序 ASCII
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("appId=").append(api.appId);
        stringBuilder.append("&bargainorId=").append(api.bargainorId);
        stringBuilder.append("&nonce=").append(api.nonce);
        stringBuilder.append("&pubAcc=").append("");
        stringBuilder.append("&tokenId=").append(api.tokenId);
    
        byte[] byteKey = (APP_KEY+"&").getBytes("UTF-8");
        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        SecretKey secretKey = new SecretKeySpec(byteKey, "HmacSHA1");
        // 生成一个指定 Mac 算法 的 Mac 对象
        Mac mac = Mac.getInstance("HmacSHA1");
        // 用给定密钥初始化 Mac 对象
        mac.init(secretKey);
        byte[] byteSrc = stringBuilder.toString().getBytes("UTF-8");
        // 完成 Mac 操作
        byte[] dst = mac.doFinal(byteSrc);
        // Base64
        api.sig = Base64.encodeToString(dst, Base64.NO_WRAP);
        api.sigType = "HMAC-SHA1";
    }
    
    /**
     *
     * QQ支付结果状态
     * */
    public void onQQResponse(BaseResponse response){
    
        Log.i("QQPay","response.retCode="+response.retCode+",response.retMsg="+response.retMsg);
    
        if(response!=null){
            switch (response.retCode){
                case 0://支付成功
                    if(mJPayListener!=null)
                        mJPayListener.onPaySuccess();
                    break;
                case -1://支付取消 用户主动取消
                    if(mJPayListener!=null)
                        mJPayListener.onPayCancel();
                    break;
                case -2://登录超时
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"登录超时");
                    break;
                case -3://重复提交订单
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"重复提交订单");
                    break;
                case -4:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"快速注册用户手机号不一致");
                    break;
                case -5:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"账号被冻结");
                    break;
                case -6:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"支付密码输入超限");
                    break;
                case -100:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"网络异常错误");
                    break;
                case -101:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"支付参数错误");
                    break;
                default:
                    if(mJPayListener!=null)
                        mJPayListener.onPayError(response.retCode,"未知错误");
    
            }
        }
    }
    

    }

    测试代码
    orderQQ = "{"appid":"10445","mch_id":"1562271","nonce_str":"58d79b407a55b4af","prepay_id":"6M6c1a02c3b0e6c4","result_code":"SUCCESS","retcode":"0","retmsg":"ok","return_code":"SUCCESS","return_msg":"SUCCESS","sign":"638E931C4B13F7F","trade_type":"APP"}";

                if(TextUtils.isEmpty(orderQQ)){
                    Toast.makeText(MainActivity.this,"预付订单为空",Toast.LENGTH_SHORT).show();
                    return;
                }
                pay.payDoraVip(MainActivity.this,"PHP", JPay.PayMode.QQPAY,orderQQ);
    

    JPay工具类,统一管理支付,好了,就写到这里,谢谢

    有问题可以加我qq:215330802
    项目地址:https://github.com/cammingcai/DoraPay

    Unity 与Android 优化通信

    https://www.jianshu.com/p/f5b20d43315a

    相关文章

      网友评论

        本文标题:Android微信支付宝QQ支付接入详解-Unity3D原生支付

        本文链接:https://www.haomeiwen.com/subject/yjmtzqtx.html