Cocos Creator Android 平台 Facebook 原生登录



在做海外项目中,经常需要接入Facebook SDK ,现将CocosCreator Android 平台 Facebook 登录的接入流程记录下来,以备有需要的朋友做参考。



一、准备工作



1、首先在facebook 开发者平台 注册账号,创建app,获取app的应用编号。



怎么注册账号,怎么创建app ,这里就不再细说。

app的应用编号和密钥,如下所示:

在这里插入图片描述



2、设置应用密钥散列



生成密钥散列有2种方式:



(1)、通过代码获取

//获取facebook所需的密钥散列
try {
	PackageInfo info = getPackageManager().getPackageInfo("com.x.x", 	 PackageManager.GET_SIGNATURES);
for (Signature signature : info.signatures) {
	MessageDigest md = MessageDigest.getInstance("SHA");
	md.update(signature.toByteArray());
	showLog("Base64 hash------" + Base64.encodeToString(md.digest(), Base64.DEFAULT));
	}
} catch (PackageManager.NameNotFoundException e) {

} catch (NoSuchAlgorithmException e) {

}



(2)、通过工具进行获取



第一步,通过命令行的方式获取到证书指纹SHA1



发布证书指纹获取方式:

keytool -exportcert -alias YOUR_RELEASE_KEY_ALIAS -keystore YOUR_RELEASE_KEY_PATH | openssl sha1 -binary | openssl base64


开发证书指纹获取方式:

keytool -exportcert -alias androiddebugkey -keystore "C:\Users\USERNAME\.android\debug.keystore" | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARY\bin\openssl" base64


证书指纹示例:

SHA1: 9D:2F:E0:3C:8E:DF:ED:8C:2B:28:88:92:60:A3:82:63:81:4F:3D:9D



第二步,使用工具,将SHA1 证书指纹转化为密钥散列



在线工具:http://tomeko.net/online_tools/hex_to_base64.php

详细使用步骤,请查看根据 sha-1 证书值获取 Facebook 的登录需要使用的散列值



密钥散列可填写多个:

在这里插入图片描述



3、添加平台



这里以添加 google play 平台为例进行说明。

(1)、点击下方“添加平台” 按钮 ,在弹出的二级页面依次选择 android ->google play 。

(2)、设置软件包名,包名就是项目包名 com.xxx.xxx。

(3)、设置类名,类名里面填写启动activity 全路径,例如:org.cocos2dx.javascript.AppActivity。



在这里插入图片描述



3、创建测试账号,修改密码



在这里插入图片描述



在这里插入图片描述



二、代码部分调整



1、在项目层 build.gradle ,引入facebook 最新版本sdk。



implementation 'com.facebook.android:facebook-login:latest.release'
implementation 'com.facebook.android:facebook-android-sdk:latest.release'


2、AndroidManifest.xml 配置



(1)、添加网络访问权限,如果已经开启,则忽略。



 <uses-permission android:name="android.permission.INTERNET"/>


(2)、在 application 添加 meta-data 元素 和针对 Facebook 的 activity 元素。



<!-- SDK Facebook start! -->
        <meta-data android:name="com.facebook.sdk.ApplicationId"
            android:value="@string/facebook_app_id"/>
        <activity android:name="com.facebook.FacebookActivity"
            android:configChanges= "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
            android:label="@string/app_name" />
<!-- SDK Facebook end! -->


(3)、在 application 启动activity 元素添加 scheme



  <activity
            android:name="org.cocos2dx.javascript.AppActivity"
            android:screenOrientation="sensorPortrait"
            android:configChanges="orientation|keyboardHidden|screenSize|screenLayout"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
            android:launchMode="singleTask"
            android:exported="true"
            android:taskAffinity="" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter  android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="@string/fb_login_protocol_scheme" />
            </intent-filter>
        </activity>


3、res/values/strings.xml 配置



    <string name="facebook_app_id">285717330186354</string>
    <string name="fb_login_protocol_scheme">fb285717330186356</string>

facebook_app_id :app的应用编号
fb_login_protocol_scheme:fb+app的应用编号



4、登录调用、回调通知、用户信息获取简单封装



关于Facebook 登录,官方提供了 LoginButton 和LoginManager 两种方式。

不过我们经常使用自己的View 来显示 ,因此这里采用 LoginManager 的方式实现。



详细请查看以下代码:

package org.cocos2dx.javascript.tools;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import com.facebook.AccessToken;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.FacebookRequestError;
import com.facebook.GraphRequest;
import com.facebook.GraphResponse;
import com.facebook.HttpMethod;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;

import org.cocos2dx.javascript.Native;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;




public class FaceBookUtils {

    private CallbackManager m_callbackManager =null;
    private String  m_actTag ="FaceBookUtils";
    private String  m_facebookLoginCallBack="";
    private Activity m_activity=null;
    private static FaceBookUtils g_Instace = null;

    public static FaceBookUtils getInstance() {
        if (null == g_Instace) {
            g_Instace = new FaceBookUtils();
        }
        return g_Instace;
    }

    public  void loginFacebook(final String callback){
        m_facebookLoginCallBack = callback;
        LoginManager.getInstance().logInWithReadPermissions(m_activity, Arrays.asList("public_profile"));
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {

        m_callbackManager.onActivityResult(requestCode,resultCode,data);
    }

    public void getUserFacebookBasicInfo(Map<String,String> inmap) {
        final String id = inmap.get("id");
        final String token = inmap.get("token");
        final String app = inmap.get("app");

        // 获取基本文本信息
        Log.d(m_actTag, "准备获取facebook用户基本信息");

        GraphRequest request = GraphRequest.newMeRequest(AccessToken.getCurrentAccessToken(), new GraphRequest.GraphJSONObjectCallback() {
            @Override
            public void onCompleted(JSONObject object, GraphResponse response) {
                if (response == null) {
                    Log.d(m_actTag, "无法获取fb用户基本信息");
                    return;
                }
                Log.d(m_actTag, "获取fb用户基本信息完毕,object是" + object);
                JSONObject responseJsonObject = response.getJSONObject();
                Log.d(m_actTag,  "而response 的object是" + responseJsonObject);//这两个jsonObject是一样的
                if (responseJsonObject == null) {
                    Log.d(m_actTag, "无法获取fb用户基本信息" + response.getError().getErrorType() + "   " + response.getError().getErrorMessage());
                    return;
                }
                Map<String,String> map = new HashMap<String, String>();
                map.put("result", "11");
                map.put("info", "fb info success");
                map.put("id", id);
                map.put("token", token);
                map.put("appid", app);
                map.put("firstName", getFacebookGraphResponseString(responseJsonObject, "first_name"));
                map.put("lastName", getFacebookGraphResponseString(responseJsonObject, "last_name"));
                map.put("userName", getFacebookGraphResponseString(responseJsonObject, "name"));
//                map.put("birthday", getFacebookGraphResponseString(responseJsonObject, "birthday"));
                //map.put("updateTime", getFacebookGraphResponseString(responseJsonObject, "updated_time"));
//                map.put("email", getFacebookGraphResponseString(responseJsonObject, "email"));
//                map.put("gender", getFacebookGraphResponseString(responseJsonObject, "gender"));

                //获取用户头像 (小)
                //JSONObject object_pic = object.optJSONObject( "picture" ) ;
                //JSONObject object_data = object_pic.optJSONObject( "data" ) ;
                //String photo = object_data.optString( "url" )  ;
                //map.put("head", photo);
                Native.nativeToLogic(m_facebookLoginCallBack,map);
            }
        });

        Bundle parameters = new Bundle();
//        parameters.putString("fields", "id,name,link,email,first_name,last_name,gender,picture,locale,timezone,updated_time,verified");
        parameters.putString("fields", "id,name,first_name,last_name");
        request.setParameters(parameters);
        request.executeAsync();
    }

    public String getFacebookGraphResponseString(JSONObject graphResponse, String flag) {
        String value = "";
        try {
            value = graphResponse.getString(flag);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Log.d(m_actTag, "getFacebookInfo flag="+flag+"   result="+value);
        return value;
    }


    public void getFacebookUserPictureAsync(String facebookUserId) {
        Log.d(m_actTag,  "getFacebookUserPictureAsync");
        Bundle parameters = new Bundle();
        parameters.putBoolean("redirect", false);
        parameters.putString("height", "200");
        parameters.putString("type", "normal");
        parameters.putString("width", "200");
        GraphRequest graphRequest= new GraphRequest(AccessToken.getCurrentAccessToken(), "/" + facebookUserId + "/picture", parameters, HttpMethod.GET, new GraphRequest.Callback() {
            public void onCompleted(GraphResponse response) {
                if (response == null) {
                    Log.d(m_actTag,  "get facebook photo fail");
                    return;
                }

                if (response.getError() != null) {
                    FacebookRequestError facebookRequestError = response.getError();
                    Log.d(m_actTag,  "get facebook photo fail 2::" + facebookRequestError.getErrorMessage());
                    return;
                }

                JSONObject responseJsonObject = response.getJSONObject();
                if (responseJsonObject == null) {
                    Log.d(m_actTag,  "get facebook photo fail 3");
                    return;
                }
                Log.d(m_actTag,  "facebook photo info:" + responseJsonObject.toString());
                String avatarUrl = "";
                try {
                    JSONObject dataJsonObject = responseJsonObject.getJSONObject("data");
                    avatarUrl = dataJsonObject.getString("url");
                    //分割出参数部分
//                    String[] sourceStrArray = avatarUrl.split("\\?");
                    avatarUrl = URLEncoder.encode(avatarUrl, "UTF-8");
                    Log.d(m_actTag,  "facebook photo avatarUrl:" + avatarUrl);
                    Map<String,String> map = new HashMap<String, String>();
                    map.put("result", "12");
                    map.put("info", "fb head success");
                    map.put("head", avatarUrl);
                    map.put("height", dataJsonObject.getString("height"));
                    map.put("width", dataJsonObject.getString("width"));
                    map.put("isSilhouette", dataJsonObject.getString("is_silhouette"));

                    Native.nativeToLogic(m_facebookLoginCallBack,map);

                } catch (Exception e) {

                    Log.d(m_actTag,  "get facebook photo fail 4"+e.getStackTrace().toString());
                }
            }
        }
        );
        Log.d(m_actTag,  "getFacebookUserPictureAsync version:"+graphRequest.getVersion()+"");
        graphRequest.executeAsync();
    }


    public void initSDK( final Activity activity){

        m_activity = activity;
        m_callbackManager = CallbackManager.Factory.create();
        Log.d("fb login","initSDK");
        LoginManager.getInstance().registerCallback(m_callbackManager, new FacebookCallback<LoginResult>() {
            @Override
            public void onSuccess(LoginResult loginResult) {
                Log.e(m_actTag, "facebook login success: " + loginResult.getAccessToken().getToken());
                Map<String,String> map = new HashMap<String, String>();
                map.put("result", "1");
                map.put("info", "fb login success");
                map.put("id", loginResult.getAccessToken().getUserId());
                map.put("token", loginResult.getAccessToken().getToken());
                map.put("app", loginResult.getAccessToken().getApplicationId());
                Native.nativeToLogic(m_facebookLoginCallBack,map);
                Log.d("fb login","success!!!!!");

                //紧接着获取用户信息
                getUserFacebookBasicInfo(map);
//                getFacebookUserPictureAsync(loginResult.getAccessToken().getUserId());
            }

            @Override
            public void onCancel() {
                Log.e(m_actTag, "facebook login cancel");
                Map<String,String> map = new HashMap<String, String>();
                map.put("result", "2");
                map.put("info", "user cancel");
                Log.d("user","cancel!!!!!");
                Native.nativeToLogic(m_facebookLoginCallBack,map);
            }

            @Override
            public void onError(FacebookException error) {
                Log.e(m_actTag, "facebook login error:" + error.toString());
                Map<String,String> map = new HashMap<String, String>();
                map.put("result", "3");
                map.put("info", error.toString());
                Log.d("facebook login","error!!!!!");
                Native.nativeToLogic(m_facebookLoginCallBack,map);
            }
        });
    }
}



5、AppActivity 中使用 FaceBookUtils 封装类



(1)、onCreate 时初始化

   
 FaceBookUtils.getInstance().initSDK(this);
   


(2)、设置回调



 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     
     FaceBookUtils.getInstance().onActivityResult(requestCode, resultCode, data);
     super.onActivityResult(requestCode, resultCode, data);
}


(3)、登录接口导出



 public static void loginFacebook(final String callback) {
      FaceBookUtils.getInstance().loginFacebook(callback);
 }



6、js 层 对java 的 Native 封装




    private static CallBackKey: string = "nativeCallback";
    private static _callBackPrefix: string; //回调集合字符前缀

    private static _prevErr = ""
    private static _hasInited = false;

    public static init() {
        if (cc.sys.isBrowser) {
            return
        }
        if (this._hasInited) {
            return
        }
        this._hasInited = true;
        window[this.CallBackKey] = {}; //回调函数集合
        this._callBackPrefix = "window." + this.CallBackKey + ".";
        //捕获异常
        if (cc.sys.isNative) {
            window.__errorHandler = function (file: any, line: any, error: any, stack: any) {
                if (this._prevErr != error + line) {
                    stack = String(stack)
                    console.log("========== GOT JS/TS ERROR ==========")
                    console.log("file:" + file, "line:" + line, "error:" + error)
                    console.log(stack)
                    this._prevErr = error + line;
                }
            }
        }
    }
    
    // 登陆fb   Native.loginFacebook((ret:any)=>{cc.log(ret)},"(%s)")
    public static loginFacebook(func: any,funcParams:string): void {
        
        if (cc.sys.isNative) {
            let cbKey: string = "loginFacebook"
            window[this.CallBackKey][cbKey] = func
            let ret = 0;
            if (cc.sys.os == cc.sys.OS_ANDROID) {
                ret = jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "loginFacebook", "(Ljava/lang/String;)V", this._callBackPrefix + cbKey + funcParams);
            }
           
        }
    }



7、js 层调用Native. loginFacebook



      getPlayerInfoBySdk(){
        let self = this;
        Native.loginFacebook((ret: any) => {
            self.facebookSdkBack(ret)
        },"(%s)")
    }
    //请求SDK返回
    facebookSdkBack(backInfo:any){
        if(backInfo){
            if(backInfo.result == "2"){//用户取消FB登录
                UIHelper.UICenterNotice(backInfo.info)
            }else if(backInfo.result == "3"){//FB登录失败
                UIHelper.UICenterNotice(backInfo.info)
            }else if(backInfo.result == "11"){//FB登录成功并返回用户数据
                this.checkFbToken(backInfo);
            }else if(backInfo.result == "12"){//FB登录成功并返回头像信息

            }
        }
    }


三、测试登录



需要注意2点:

(1)、使用的打包证书需要与facebook 开发者平台生成密钥散列证书一致。

(2)、需要使用 facebook 测试账号进行登录测试。



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

w风雨无阻w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值