1. 程式人生 > >cocos2dx3.15接入微信SDK實現登入和分享android studio2.3.3

cocos2dx3.15接入微信SDK實現登入和分享android studio2.3.3

首先開始呢,我必須得吐槽一下網上的教程以及微信開放平臺官網,網上的教程主要是太老了程式碼雖然都能用但是不完整有的東西已經改了,官網就不用說了,文件垃圾,是很垃圾。參考作用幾乎等於沒有,唯一作用就是檢視返回值以及一些引數有什麼用。嗯對的。沒話說。

現在開始教程:

第一步:
準備好你的APP_ID這個東西不解釋了。如果不知道請先去微信開放平臺 檢視一下注冊你的應用程式。然後登入功能是收費的,分享是免費的
下面是註冊應用程式的步驟:
開啟微信開放平臺官網:
第一步

點選建立應用,按照提示輸入好之後點選下一步。:
第二步

填寫完了之後就提交稽核,一般的話稽核可能1-3天就好了
第三步

以安卓為例子,簽名和包名必須要和你要接入的cocos專案的包名和簽名一致,對於簽名的獲取請看下圖:
第四步

開啟 Android資源下載之後在右邊下滑找到:
第四步

下載安裝到手機上,我這裡用的模擬器,然後把你們要接入的cocos專案也打包好安裝的手機上之後開啟之前安裝的簽名生成工具:
第五步

開啟工具之後輸入你的包名:
第六步
這個就是簽名的獲取

應用註冊稽核通過之後開始下一步

第二步:
將你的cocos專案匯入到android studio2.3.3,其他環境參照相應的教程匯入專案,但是推薦用android studio方便,匯入方法如下:
第一步
第二步
第四步

專案匯入之後配置一下微信SDK的環境只需要一句話就可以了,但是前提是你電腦能夠聯網下載微信SDK:
第五步

把這一句話加上就行了:'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'

接下來就可以開始寫程式碼了,首先是Java端的程式碼,程式碼比較簡單,我也不是很瞭解Java所以我就不逐行解釋了,基本上直接複製就可以使用了。

首先開啟這個檔案:
第一步

下面是java端的程式碼:

package org.cocos2dx.cpp;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import
android.util.Log; import android.widget.Toast; import com.qt.NiuBuTing.R; import com.qt.NiuBuTing.wxapi.WXEntryActivity; import com.tencent.mm.opensdk.modelmsg.SendAuth; import com.tencent.mm.opensdk.modelmsg.SendMessageToWX; import com.tencent.mm.opensdk.modelmsg.WXMediaMessage; import com.tencent.mm.opensdk.modelmsg.WXWebpageObject; import com.tencent.mm.opensdk.openapi.IWXAPI; import com.tencent.mm.opensdk.openapi.WXAPIFactory; import org.cocos2dx.lib.Cocos2dxActivity; import java.io.ByteArrayOutputStream; public class AppActivity extends Cocos2dxActivity { public static final String TAG = "NiuBuTing_Weixin_SDK"; public static final String APP_ID = "這裡填寫你的Appid"; public static IWXAPI api; private static AppActivity instance = null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); instance = this; // 註冊到微信 regToWx(); } //註冊到微信 private void regToWx() { //工廠模式建立微信api api = WXAPIFactory.createWXAPI(this, APP_ID, false); //註冊程式 api.registerApp(APP_ID); } //啟動微信 private static boolean LaunchWX() { boolean ret = false; if (!api.isWXAppInstalled()) {//判斷是否安裝微信 Toast.makeText(instance, "沒有安裝微信,請先安裝微信!", Toast.LENGTH_LONG).show(); return ret; } if (api.openWXApp()) {//判斷開啟微信是否成功 Log.d(TAG, "微信開啟成功!"); ret = true; } else { Log.d(TAG, "微信開啟失敗!"); ret = false; } return ret; } //將圖片解析成一個二進位制陣列 private byte[] bmpToByteArrar(final Bitmap bitmap, final boolean isRecycle){ ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); if (isRecycle) { bitmap.recycle(); } byte[] result = outputStream.toByteArray(); try { outputStream.close(); } catch (Exception e) { e.printStackTrace(); } return result; } //微信登入 public static void WXLogin(){ Log.d(TAG, "login-------------"); WXEntryActivity.ReqState = 0; final SendAuth.Req req = new SendAuth.Req(); req.scope = "snsapi_userinfo"; //這裡不能改 req.state = "QTNiuBuTing"; //這裡改成你自己的資料 api.sendReq(req); } //分享到聊天視窗 public static void WXShareMsgToFriends(final String userNickName, final String roomNum, final String inningsNum, final String peopleNum, final int playType){ //這裡的引數是看你自己你需要的話就行,但是在cocos裡面呼叫這個方法的你也傳遞數值過來 String strPlayType = "輪莊牛牛"; if (playType == 1) //2為輪莊 { strPlayType = "搶莊牛牛"; } WXEntryActivity.ReqState = 1; //封裝一個連結,點選跳轉到指定網址 WXWebpageObject webpag = new WXWebpageObject(); webpag.webpageUrl = "http://www.0791youxi.com/"; //封裝遊戲圖示 Bitmap bitmap = BitmapFactory.decodeResource(instance.getResources(), R.mipmap.icon); Bitmap thumb = Bitmap.createScaledBitmap(bitmap, 108, 108, true); bitmap.recycle(); //封裝分享內容 WXMediaMessage msg = new WXMediaMessage(webpag); msg.thumbData = instance.bmpToByteArrar(thumb, true); msg.title = "我是 " + userNickName; //這個是標題 msg.description = "[" + strPlayType + "]" //這個是描述 + " 房間號:" + roomNum + "。" + " 局數:" + inningsNum + "。" + " 人數:" + peopleNum + "人。" + "約麼? 我在QT牛不停建立了房間,一起來玩一玩吧!"; //封裝請求 SendMessageToWX.Req req = new SendMessageToWX.Req(); req.transaction = buildTransaction("webpag"); req.message = msg; req.scene = SendMessageToWX.Req.WXSceneSession; //傳送請求 api.sendReq(req); } //生成一個微信唯一請求識別符號 private static String buildTransaction(final String type) { return (type == null) ? String.valueOf(System.currentTimeMillis()) : type + System.currentTimeMillis(); } }

微信登入請求和分享請求傳送後還需要建立一個類提供給微信SDK回撥,現在你需要新建一個包,包名必須為wxapi,而且這個包必須要在cocos包名的目錄下,比如你包名是com.csn.cocosNew 那麼新建的這包就是com.csn.cocosNew.wxapi,然後在這個包下面新建一個WXEntryActivity類,類名也是必須這樣,沒辦法微信的要求,下面是建立的方法:
首先是建立包:
第一步
第二步
包名輸你自己的別輸我演示的這個,然後點選OK

接下來是建立類:
第三步
類建立的時候在你剛才新建的包名目錄下右鍵單擊就可以了

記得類名必須是WXEntryActivity!!! 其他的預設就行了

全部建立好之後檔案結構是這樣的:
結果

然後雙擊開啟,開始寫回調:

下面是WXEntryActivity類裡面的完整程式碼:

package 你的專案包名.wxapi;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

import com.tencent.mm.opensdk.modelbase.BaseReq;
import com.tencent.mm.opensdk.modelbase.BaseResp;
import com.tencent.mm.opensdk.modelmsg.SendAuth;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler;

import org.cocos2dx.cpp.AppActivity;
import org.cocos2dx.cpp.tools.JniHelper;

/**
 * Created by Administrator on 2017/6/5.
 */

public class WXEntryActivity extends Activity implements IWXAPIEventHandler {
    private final String TAG = "NiuBuTing_Weixin_SDK";
    public static int ReqState = -1;  //0為登入, 1為分享

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        AppActivity.api.handleIntent(this.getIntent(), this);
        //如果沒回調onResp,八成是這句沒有寫
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        setIntent(intent);
        AppActivity.api.handleIntent(intent, this);
    }

    // 微信傳送請求到第三方應用時,會回撥到該方法
    @Override
    public void onReq(BaseReq req) {
        finish();
    }

    @Override
    public void onResp(BaseResp resp) {
        Log.d(TAG, "onResp:");
        switch (resp.errCode) {
            case BaseResp.ErrCode.ERR_OK:
                Log.d(TAG, "請求成功");
                if (ReqState == 0)  //這個是自己加用於判斷是登入還是分享,你們可以去掉判斷只要裡面的程式碼就行了
                {
                    SendAuth.Resp sendResp = (SendAuth.Resp) resp;
                    JniHelper.onResp(sendResp.code); //這個登入了之後用於回撥cocos端函式的對映程式碼
                    Log.d(TAG, sendResp.code);
                }
                break;
            case BaseResp.ErrCode.ERR_USER_CANCEL:
                //傳送取消
                Toast.makeText(this, "請求取消", Toast.LENGTH_LONG).show();
                break;
            case BaseResp.ErrCode.ERR_AUTH_DENIED:
                //傳送被拒絕
                Toast.makeText(this, "請求被拒絕", Toast.LENGTH_LONG).show();
                break;
            default:
                //傳送返回
                Toast.makeText(this, "請求返回", Toast.LENGTH_LONG).show();
                break;
        }
        ReqState = -1;
        finish();
    }
}

這裡是JniHelper這個類裡面的程式碼。這裡面你們要自己建立一個,建立在那個包下面都無所謂:
我是建立在這兒:
JniHelper

下面是程式碼

package org.cocos2dx.cpp.tools;

/**
 * Created by Administrator on 2017/6/5.
 */

public class JniHelper {
    public static native void onResp(String code);
}

做完這些之後還需要新增相應的許可權,在AndroidMainfest.xml檔案裡面新增,下面附上我的檔案,你們根據要求自己更改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qt.NiuBuTing"
    android:installLocation="auto">

    <uses-feature android:glEsVersion="0x00020000" />
     <!--這些是微信必須的許可權 -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
        android:label="@string/app_name"
        android:allowBackup="true"
        android:icon="@mipmap/icon">

        <!-- Tell Cocos2dxActivity the name of our .so -->
        <meta-data android:name="android.app.lib_name"
                   android:value="MyGame" />

        <activity
            android:name="org.cocos2dx.cpp.AppActivity"
            android:screenOrientation="landscape"
            android:configChanges="orientation|keyboardHidden|screenSize"
            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>

        <!--註冊微信回撥 WXEntryActivity -->
        <activity
            android:name=".wxapi.WXEntryActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:launchMode="singleTask"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />

    </application>

</manifest>

以上步驟完成了之後就可以還可以在cocos裡面使用了。

下面開始說cocos裡面的使用,我的使用方法是新建一個類專門用訪問微信的是一個單例:
下面附上完整程式碼,首先是.h檔案

#ifndef __WXAPIMANAGER_H__
#define __WXAPIMANAGER_H__

#include "cocos2d.h"
#include "network/HttpClient.h"

USING_NS_CC;
using namespace network;

typedef std::function<void(std::string &data)> LastCallBack;

#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)  //判斷是不是安卓環境
#include "platform/android/jni/JniHelper.h"
#endif

typedef enum {
    REQ_ERROR = 0,
    REQ_SUCCESS,
    CMD_ACCESS_TOKEN,
    CMD_USER_INFO,
    DEFAULT
}reqTag;

class WXAPIManager : Ref
{
public:
    static WXAPIManager *getInstance();

    //分享到好友
    void sendToFriend(const char *userNickName, const char *roomNum, const char *inningsNum, const char *peopleNum, const int playType);

    //微信登入
    void loginWX();

public:
    static WXAPIManager *_instance;

    //http請求
    void WX_RequestHttp(const char *url, const std::string &data);

    //請求的回撥
    void onResponse(HttpClient *client, HttpResponse *response);

    //最終回撥
    void onTheEndResponse(std::string &data);

private:
    WXAPIManager();
    ~WXAPIManager();

    reqTag lastTag;
};
#endif // __WXAPIMANAGER_H__

接下來是.cpp的程式碼:

#include "WXAPIManager.h"

WXAPIManager *WXAPIManager::_instance = nullptr;

WXAPIManager::WXAPIManager()
:lastTag(reqTag::CMD_ACCESS_TOKEN)
{
}

WXAPIManager::~WXAPIManager()
{
}

WXAPIManager *WXAPIManager::getInstance()
{
    if (_instance == nullptr)
    {
        _instance = new(std::nothrow) WXAPIManager();
        _instance->autorelease();
        _instance->retain();
    }

    return _instance;
}

//分享給好友
void WXAPIManager::sendToFriend(const char *userNickName, const char *roomNum, const char *inningsNum, const char *peopleNum, const int playType)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) //判斷是不是Android環境
    JniMethodInfo minfo;

        //呼叫java端的靜態函式
        bool isHave = JniHelper::getStaticMethodInfo(minfo, 
            "org/cocos2dx/cpp/AppActivity", //這個是固定的
            "WXShareMsgToFriends",   //這個是你要呼叫的java端的函式名
            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V");
            //後面跟的是java那邊需要接收的引數

    if (!isHave) {
        log("jni:WXShareImgToFriends is null");
    }
    else {
        //這裡需要把引數轉換為java格式
        jstring jUserNickName = minfo.env->NewStringUTF(userNickName);
        jstring jRoomNum = minfo.env->NewStringUTF(roomNum);
        jstring jInnings = minfo.env->NewStringUTF(inningsNum);
        jstring jpeopleNum = minfo.env->NewStringUTF(peopleNum);
        jint jPlayType = playType;

        minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID, jUserNickName, jRoomNum, jInnings, jpeopleNum, jPlayType);  //開始呼叫函式

        //刪除引數
        minfo.env->DeleteLocalRef(jUserNickName);
        minfo.env->DeleteLocalRef(jRoomNum);
        minfo.env->DeleteLocalRef(jInnings);
        minfo.env->DeleteLocalRef(jpeopleNum);
    }
#endif
}

//微信登入
void WXAPIManager::loginWX()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
    JniMethodInfo minfo;

    bool isHave = JniHelper::getStaticMethodInfo(minfo,
        "org/cocos2dx/cpp/AppActivity",
        "WXLogin",
        "()V");  //沒有引數

    if (!isHave) {
        log("jni:WXLogin is null");
    }
    else
    {
        minfo.env->CallStaticVoidMethod(minfo.classID, minfo.methodID);
    }   
#endif
}

//http請求
void WXAPIManager::WX_RequestHttp(const char *url, const std::string &data)
{
    log("WXAPIManager----------------WX_RequestHttp:");
    HttpRequest* request = new HttpRequest();
    //設定請求型別  
    request->setRequestType(HttpRequest::Type::GET);
    request->setUrl(url);
    //設定回撥函式  
    request->setResponseCallback(CC_CALLBACK_2(WXAPIManager::onResponse, this));
    request->setRequestData(data.c_str(), data.size());

    HttpClient* httpClient = HttpClient::getInstance();
    void onResponse(HttpClient *client, HttpResponse *response);
    //設定超時時間
    httpClient->setTimeoutForConnect(10);
    httpClient->setTimeoutForRead(10);
    httpClient->send(request);
    request->release();
}

//請求回撥
void WXAPIManager::onResponse(HttpClient *client, HttpResponse *response)
{
    log("WXAPIManager----------------onResponse:");
    if (!response) {
        CCLOG("Log:response =null,plase check it.");
        return;
    }

    //請求失敗  
    if (!response->isSucceed())
    {
        CCLOG("ERROR BUFFER:%s", response->getErrorBuffer());
        return;
    }

    int codeIndex = response->getResponseCode();
    const char* tag = response->getHttpRequest()->getTag();

    //請求成功  
    std::vector<char>* buffer = response->getResponseData();
    std::string temp(buffer->begin(), buffer->end());
    log("temp OpenID = %s", temp.c_str());

    if (lastTag == reqTag::CMD_ACCESS_TOKEN)
    {
        //拿到access_token之後還需要繼續請求,最終才能拿到使用者資訊,這點官網上有解釋
        LastCallBack callback = CC_CALLBACK_1(WXAPIManager::onTheEndResponse, this);
        callback(temp);
    }
    else if(lastTag == reqTag::CMD_USER_INFO)
    {
        //這裡代表拿到使用者資訊,你就可以開始做你自己的處理了
    }
}

//最終回撥
void WXAPIManager::onTheEndResponse(std::string &data)
{
    log("data = %s", data.c_str());
    if (data == "")
    {
        return;
    }


    const char *WX_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=";
    const char *WX_USER_OPEN_ID = "&openid=";

    char url[512];
    strcpy(url, WX_USER_INFO_URL);
    strcat(url, access_token);  //上一步拿到的access_token
    strcat(url, WX_USER_OPEN_ID);
    strcat(url, openid);  //上一步拿到的openid

    CCLOG("%s", url);
    lastTag = reqTag::CMD_USER_INFO;

    //繼續請求使用者資訊
    WXAPIManager::WX_RequestHttp(url, "");
}

#if(CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
//必須是C語言的函式,因為C++的函式會有不同的符號生成規則  
//1.Java_:是格式,必須加的  
//2.org_cocos2dx_cpp_tools_JniHelper:是包名+類名  
//3.onResp:是Andriod工程中宣告的名字  
//4.中間需要_分開  
extern "C" {

    //給android呼叫的native程式碼,微信回撥後會呼叫這個函式
    //這個程式碼是給安卓呼叫,那邊傳了一個code過來直接轉換之後使用就行了
    /*
        微信的登入的流程:
            1、拉起微信登入介面,使用者確認之後就回調java端的回撥。
            2、Java端的回撥執行之後根據程式碼在呼叫這個函式。
            3、接下來的步驟有cocos基礎的基本都知道怎麼執行了
            所以在cocos端首先執行的就是這裡的程式碼。
    */
    JNIEXPORT void Java_org_cocos2dx_cpp_tools_JniHelper_onResp(JNIEnv *env, jobject thiz, jstring code)
    {
        const char *szCode = env->GetStringUTFChars(code, NULL);

        const char *WX_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=";
        const char *WX_APP_ID = "這裡是你的APPID";
        const char *WX_SECRET = "&secret=官網查詢你的AppSecret";  //沒有獲取過的就點旁邊的生成就可以了
        const char *WX_CODE = "&code=";
        const char *WX_GRANT_TYPE = "&grant_type=authorization_code";

        char url[512];
        strcpy(url, WX_ACCESS_TOKEN_URL);
        strcat(url, WX_APP_ID);
        strcat(url, WX_SECRET);
        strcat(url, WX_CODE);
        strcat(url, szCode);
        strcat(url, WX_GRANT_TYPE);

        CCLOG("JniHelper_onResp url = %s", url);
        CCLOG("szCode = %s", szCode);
        WXAPIManager *_twm = WXAPIManager::getInstance();
        _twm->WX_RequestHttp(url, "");

        env->ReleaseStringUTFChars(code, szCode);
    }
}
#endif

程式碼完成之後,自己修改好就可以開始除錯了。不要被我的程式碼影響,只是給你一個參考和告訴你執行流程而已。cocos端的知道流程之後更多的就看你自己的基礎了。

還有兩點有的人可能看了別人教程之後才看到我的,用的也是別人的程式碼,有部分程式碼是有BUG的,比如你發現分享之後選擇回到自己的遊戲的時候,回不去被卡在那兒了。這種情況主要是你在 ”分享“的這個函式的最後加入一個finish();函式。遇到這個問題的可以把這個函式刪了再試試。

教程就到這兒結束,全手打很辛苦,有幫助就點個贊然後關注一下咯。有講解的不到位或是錯誤的還請大家留言指正,有問題也可以留言或者加入我的QQ群:249155914,一起討論!謝謝大家