ZeroyiQ:Unity 多平台原生SDK接入速览(一):微信开放平台
ZeroyiQ:Unity 多平台原生SDK接入速览(二):QQ互联
ZeroyiQ:Unity 多平台原生SDK接入速览(四):Twitter
ZeroyiQ:Unity 多平台原生SDK接入速览(五):微博
一、前言
由于该系列为了能适应更多的引擎,因此主要还是选择了对于原生SDK的研究。这里接入的就是 Facebook-Android-SDK。
如果只是 Unity 平台接入 Facebook 的话,还是推荐直接使用官方提供的 Unity特供版本,使用起来简单易上手。
Facebook 开发平台可以直接通过 Facebook 账户直接登录,当前(2020-7-1)由于新冠疫情,个人开发者验证已暂停,只能进行企业认证。但是依旧能够创建应用,获取应用编号。
在创建应用并且添加 Facebook 登录的产品后,能够选快速启动的教程,官方提供了很完善的引导。官方项目中也包含较完善的 Demo。
二、SDK 接入
1. 添加包管理仓库
在工程的 build.gradle (Project) 文件中增加 mavenCentral。
buildscript {
repositories {
mavenCentral()
}
}
2. 添加依赖
在需要接入SDK的模块的 build.gradle (Module: app) 文件中增加依赖,之后编译即可使用。
dependencies {
implementation 'com.facebook.android:facebook-android-sdk:[4,5)'
}
3. 后台设置秘钥散列
Facebook 为了验证应用的请求的正确性,保证之间的安全,还需要提供开发环境或者发布后的秘钥散列。
生成秘钥依赖如下:
- Java 开发包中的密钥和证书管理工具 (keytool)
- Google Code Archive 的 Windows 版 openssl-for-windows OpenSSL 库
开发环境
如果环境没有配置好,keytool 和 openssl 都可以使用绝对路径,xxxopenssl-0.9.8e_X64inopenssl.exe。
keytool -exportcert -alias androiddebugkey -keystore "C:UsersUSERNAME.androiddebug.keystore" | "PATH_TO_OPENSSL_LIBRARYinopenssl" sha1 -binary | "PATH_TO_OPENSSL_LIBRARYinopenssl" base64
发布后
YOUR_RELEASE_KEY_ALIAS 密钥别名
YOUR_RELEASE_KEY_PATH 密钥路径
keytool -exportcert -alias YOUR_RELEASE_KEY_ALIAS -keystore YOUR_RELEASE_KEY_PATH | openssl sha1 -binary | openssl base64
4. 设置 Android 相关配置
AndroidManifest.xml 中申请网络权限。
resvaluesstrings.xml (没有该文件,自己创建一个)中添加 AppId 和登录 scheme。
<string name="facebook_app_id">561412404767402</string>
<!--scheme 格式为 fb + appid-->
<string name="fb_login_protocol_scheme">fb561412404767402</string>
AndroidManifest.xml 中添加 meta-data 和 activity 的配置。
<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" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter><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>
5. 实现回调
创建 callbackManager,以便处理回调,可以在 OnCreate 的时候调用如下代码进行初始化。
callbackManager = CallbackManager.Factory.create();
在登录和分享中,都可以调用各自的 registerCallback ,传入初始化后的 callbackManager 和 FacebookCallback 接口,并实现 FacebookCallback 中的回调方法。
三、登录
1. 添加依赖
build.gradle 中添加。
implementation 'com.facebook.android:facebook-login:[5,6)'
2. 发起请求
Facebook 提供一个 LoginButton 的登录元素,直接添加到界面。通过点击按钮就能直接发起登录请求。还有一种就是自定义按钮,通过登录 Manager,主动发起登录请求,这里演示两种方式登录。
2.a Facebook 原生按钮
布局 xml 中添加。
<com.facebook.login.widget.LoginButton
android:id="@+id/login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:layout_marginBottom="30dp" />
直接通过 LoginButton 绑定回调,也能通过登录 Manager,两种方式二选一,具体见下文自定义按钮。
loginButton = (LoginButton) findViewById(R.id.login_button);
// 设置登录用户域
loginButton.setReadPermissions("email");
// 如果 loginbutton 放在一个 fragment 中需要添加如下
loginButton.setFragment(this);
// LoginButton 注册 callback
loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
// App code
}
@Override
public void onCancel() {
// App code
}
@Override
public void onError(FacebookException exception) {
// App code
}
});
2.b 自定义按钮(Unity 中触发)
直接通过 logInWithReadPermissions 方法触发登录请求。
public void login(Activity activity) {
// 判断当前 accessToken 是否已经存在(已登录)并且 accessToken 未过期
if (!AccessToken.isCurrentAccessTokenActive()) {
LoginManager.getInstance().registerCallback(callbackManager,
new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
UnityCallApi.unityLogInfo(TAG, "Login successful.");
getUserInfo();
}
@Override
public void onCancel() {
UnityCallApi.unityLogInfo(TAG, "Login cancel.");
}
@Override
public void onError(FacebookException error) {
error.printStackTrace();
UnityCallApi.unityLogError(TAG, "Login Error" + error.toString());
}
});
// 主动发起请求,public_profile 为基本用户域
LoginManager.getInstance().logInWithReadPermissions(activity, Arrays.asList("public_profile"));
}
}
3. onActivityResult 中传递结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
callbackManager.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
}
四、获取用户信息
private void getUserInfo() {
// 个人 me 请求,注册请求回调
GraphRequest request = GraphRequest.newMeRequest(
AccessToken.getCurrentAccessToken(),
new GraphRequest.GraphJSONObjectCallback() {
@Override
public void onCompleted(JSONObject object, GraphResponse response) {
FacebookRequestError error = response.getError();
if (null != object && TextUtils.isEmpty(error.getErrorMessage())) {
UnityCallApi.unityLogInfo(TAG, "Get User Info Successful.");
UnityCallApi.sendLoginInfoToUnity(true, object.toString());
} else {
UnityCallApi.unityLogError(TAG, String.format("Get User Info Failed.Code: %s Msg: %s", error.getErrorCode(), error.getErrorMessage()));
UnityCallApi.sendLoginInfoToUnity(false, "");
}
}
}
);
Bundle parameters = new Bundle();
// 设置请求字段
parameters.putString("fields", "id,name,gender");
request.setParameters(parameters);
request.executeAsync();
}
五、分享
Build.gradle 中添加依赖
implementation 'com.facebook.android:facebook-share:[5,6)'
设置分享回调,可以和 2.5 设置回调一起初始化。
shareDialog = new ShareDialog(activity);
shareDialog.registerCallback(callbackManager, new FacebookCallback<Sharer.Result>() {
@Override
public void onSuccess(Sharer.Result result) {
UnityCallApi.unityLogInfo(TAG, "Share Successful.");
}
@Override
public void onCancel() {
UnityCallApi.unityLogInfo(TAG, "Share Cancel.");
}
@Override
public void onError(FacebookException error) {
UnityCallApi.unityLogError(TAG, String.format("Share Error.Msg:%s", error.toString()));
}
});
1. 网页
public void shareWebLink(Bundle params) {
if (ShareDialog.canShow(ShareLinkContent.class)) {
ShareLinkContent content = new ShareLinkContent.Builder()
.setContentUrl(Uri.parse("网页"))
.build();
shareDialog.show(content);
}
}
2. 图片
分享图片或者视频的时候,必须要在 AndroidManifest.xml 中配置 provider, authorities 格式为 com.facebook.app.FacebookContentProvider+appid。
<provider
android:name="com.facebook.FacebookContentProvider"
android:authorities="com.facebook.app.FacebookContentProvider{APPID}"
android:exported="true" />
分享代码
public void shareImage(Bundle params) {
if (ShareDialog.canShow(SharePhotoContent.class)) {
SharePhoto photo = new SharePhoto.Builder()
.setBitmap(bitmap) // bitmap 图片
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
shareDialog.show(content);
}
}
六、总结
Facebook 对于 accessToken 封装的很好,可以直接通过静态方法直接进行判断,使用起来比较规整。对于申请用户域,Facebook 有套很完整的规则文档。