|
|
@@ -0,0 +1,502 @@
|
|
|
+package com.cocos.plugin;
|
|
|
+
|
|
|
+import android.app.Activity;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.Bundle;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.cocos.lib.CocosHelper;
|
|
|
+import com.cocos.lib.JsbBridgeWrapper;
|
|
|
+import com.cocos.service.SDKWrapper;
|
|
|
+import com.facebook.AccessToken;
|
|
|
+import com.facebook.CallbackManager;
|
|
|
+import com.facebook.FacebookCallback;
|
|
|
+import com.facebook.FacebookException;
|
|
|
+import com.facebook.FacebookSdk;
|
|
|
+import com.facebook.appevents.AppEventsLogger;
|
|
|
+import com.facebook.login.LoginManager;
|
|
|
+import com.facebook.login.LoginResult;
|
|
|
+import com.facebook.share.Sharer;
|
|
|
+import com.facebook.share.model.ShareHashtag;
|
|
|
+import com.facebook.share.model.ShareLinkContent;
|
|
|
+import com.facebook.share.widget.ShareDialog;
|
|
|
+
|
|
|
+import org.json.JSONArray;
|
|
|
+import org.json.JSONException;
|
|
|
+import org.json.JSONObject;
|
|
|
+
|
|
|
+import java.lang.ref.WeakReference;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Currency;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+import java.util.regex.Pattern;
|
|
|
+
|
|
|
+public final class FBWrapper implements SDKWrapper.SDKInterface {
|
|
|
+ private static final String REQUEST_EVENT = "facebook.request";
|
|
|
+ private static final String RESPONSE_EVENT = "facebook.response";
|
|
|
+ private static final int MAX_EVENT_PARAMETERS = 25;
|
|
|
+ private static final int MAX_EVENT_PARAMETER_LENGTH = 100;
|
|
|
+ private static final Pattern EVENT_NAME_PATTERN =
|
|
|
+ Pattern.compile("^[A-Za-z0-9][A-Za-z0-9 _-]{1,39}$");
|
|
|
+
|
|
|
+ private WeakReference<Activity> activityRef = new WeakReference<>(null);
|
|
|
+ private CallbackManager callbackManager;
|
|
|
+ private ShareDialog shareDialog;
|
|
|
+ private AppEventsLogger appEventsLogger;
|
|
|
+ private JsbBridgeWrapper.OnScriptEventListener requestListener;
|
|
|
+ private String initializationError;
|
|
|
+ private String pendingLoginRequestId;
|
|
|
+ private String pendingShareRequestId;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void init(Context context) {
|
|
|
+ if (!(context instanceof Activity)) {
|
|
|
+ initializationError = "Facebook SDK 初始化需要 Activity Context。";
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Activity activity = (Activity) context;
|
|
|
+ activityRef = new WeakReference<>(activity);
|
|
|
+ registerBridgeListener();
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (!FacebookSdk.isInitialized()) {
|
|
|
+ throw new IllegalStateException(
|
|
|
+ "Facebook SDK 尚未初始化,请检查 Manifest 中的 App ID、Client Token 和 AutoInit 配置。"
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ callbackManager = CallbackManager.Factory.create();
|
|
|
+ appEventsLogger = AppEventsLogger.newLogger(context.getApplicationContext());
|
|
|
+ registerLoginCallback();
|
|
|
+ registerShareCallback(activity);
|
|
|
+ initializationError = null;
|
|
|
+ } catch (Throwable error) {
|
|
|
+ initializationError = safeMessage(error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void registerBridgeListener() {
|
|
|
+ requestListener = this::handleRequest;
|
|
|
+ JsbBridgeWrapper.getInstance().addScriptEventListener(REQUEST_EVENT, requestListener);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void registerLoginCallback() {
|
|
|
+ LoginManager.getInstance().registerCallback(
|
|
|
+ callbackManager,
|
|
|
+ new FacebookCallback<LoginResult>() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess(LoginResult result) {
|
|
|
+ String requestId = takePendingLoginRequestId();
|
|
|
+ if (requestId == null) return;
|
|
|
+
|
|
|
+ AccessToken token = result != null ? result.getAccessToken() : null;
|
|
|
+ if (token == null || token.getToken() == null || token.getToken().isEmpty()) {
|
|
|
+ dispatchError(requestId, "login", "EMPTY_ACCESS_TOKEN", "Facebook 登录成功但未返回 Access Token。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ putQuietly(data, "accessToken", token.getToken());
|
|
|
+ putQuietly(data, "userId", token.getUserId());
|
|
|
+ dispatchSuccess(requestId, "login", false, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onCancel() {
|
|
|
+ String requestId = takePendingLoginRequestId();
|
|
|
+ if (requestId != null) {
|
|
|
+ dispatchSuccess(requestId, "login", true, new JSONObject());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(FacebookException error) {
|
|
|
+ String requestId = takePendingLoginRequestId();
|
|
|
+ if (requestId != null) {
|
|
|
+ dispatchError(requestId, "login", "LOGIN_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ private void registerShareCallback(Activity activity) {
|
|
|
+ shareDialog = new ShareDialog(activity);
|
|
|
+ shareDialog.registerCallback(
|
|
|
+ callbackManager,
|
|
|
+ new FacebookCallback<Sharer.Result>() {
|
|
|
+ @Override
|
|
|
+ public void onSuccess(Sharer.Result result) {
|
|
|
+ String requestId = takePendingShareRequestId();
|
|
|
+ if (requestId == null) return;
|
|
|
+
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ if (result != null && result.getPostId() != null) {
|
|
|
+ putQuietly(data, "postId", result.getPostId());
|
|
|
+ }
|
|
|
+ dispatchSuccess(requestId, "share", false, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onCancel() {
|
|
|
+ String requestId = takePendingShareRequestId();
|
|
|
+ if (requestId != null) {
|
|
|
+ dispatchSuccess(requestId, "share", true, new JSONObject());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onError(FacebookException error) {
|
|
|
+ String requestId = takePendingShareRequestId();
|
|
|
+ if (requestId != null) {
|
|
|
+ dispatchError(requestId, "share", "SHARE_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleRequest(String rawRequest) {
|
|
|
+ String requestId = "";
|
|
|
+ String method = "unknown";
|
|
|
+ try {
|
|
|
+ JSONObject request = new JSONObject(rawRequest == null ? "{}" : rawRequest);
|
|
|
+ requestId = request.optString("requestId", "").trim();
|
|
|
+ method = request.optString("method", "").trim();
|
|
|
+ JSONObject params = request.optJSONObject("params");
|
|
|
+ if (params == null) params = new JSONObject();
|
|
|
+
|
|
|
+ if (requestId.isEmpty() || method.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("Facebook 请求缺少 requestId 或 method。 ");
|
|
|
+ }
|
|
|
+
|
|
|
+ if ("init".equals(method)) {
|
|
|
+ handleInit(requestId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (initializationError != null) {
|
|
|
+ dispatchError(requestId, method, "NOT_INITIALIZED", initializationError);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (method) {
|
|
|
+ case "login":
|
|
|
+ handleLogin(requestId, params);
|
|
|
+ break;
|
|
|
+ case "logout":
|
|
|
+ handleLogout(requestId);
|
|
|
+ break;
|
|
|
+ case "share":
|
|
|
+ handleShare(requestId, params);
|
|
|
+ break;
|
|
|
+ case "logEvent":
|
|
|
+ handleLogEvent(requestId, params);
|
|
|
+ break;
|
|
|
+ case "logPurchase":
|
|
|
+ handleLogPurchase(requestId, params);
|
|
|
+ break;
|
|
|
+ case "flushEvents":
|
|
|
+ handleFlushEvents(requestId);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ dispatchError(requestId, method, "UNKNOWN_METHOD", "不支持的 Facebook 方法:" + method);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } catch (Throwable error) {
|
|
|
+ dispatchError(requestId, method, "INVALID_REQUEST", safeMessage(error));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleInit(String requestId) {
|
|
|
+ if (initializationError != null) {
|
|
|
+ dispatchError(requestId, "init", "INIT_ERROR", initializationError);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ putQuietly(data, "sdkVersion", FacebookSdk.getSdkVersion());
|
|
|
+ dispatchSuccess(requestId, "init", false, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleLogin(String requestId, JSONObject params) {
|
|
|
+ if (pendingLoginRequestId != null) {
|
|
|
+ dispatchError(requestId, "login", "LOGIN_IN_PROGRESS", "已有 Facebook 登录请求正在进行。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final Activity activity = activityRef.get();
|
|
|
+ if (activity == null || activity.isFinishing()) {
|
|
|
+ dispatchError(requestId, "login", "ACTIVITY_UNAVAILABLE", "Android Activity 不可用。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final List<String> permissions = parsePermissions(params.optJSONArray("permissions"));
|
|
|
+ pendingLoginRequestId = requestId;
|
|
|
+ activity.runOnUiThread(() -> {
|
|
|
+ try {
|
|
|
+ LoginManager.getInstance().logInWithReadPermissions(activity, permissions);
|
|
|
+ } catch (Throwable error) {
|
|
|
+ pendingLoginRequestId = null;
|
|
|
+ dispatchError(requestId, "login", "LOGIN_START_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleLogout(String requestId) {
|
|
|
+ final Activity activity = activityRef.get();
|
|
|
+ if (activity == null || activity.isFinishing()) {
|
|
|
+ dispatchError(requestId, "logout", "ACTIVITY_UNAVAILABLE", "Android Activity 不可用。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ activity.runOnUiThread(() -> {
|
|
|
+ try {
|
|
|
+ LoginManager.getInstance().logOut();
|
|
|
+ dispatchSuccess(requestId, "logout", false, new JSONObject());
|
|
|
+ } catch (Throwable error) {
|
|
|
+ dispatchError(requestId, "logout", "LOGOUT_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleShare(String requestId, JSONObject params) {
|
|
|
+ if (pendingShareRequestId != null) {
|
|
|
+ dispatchError(requestId, "share", "SHARE_IN_PROGRESS", "已有 Facebook 分享请求正在进行。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final Activity activity = activityRef.get();
|
|
|
+ if (activity == null || activity.isFinishing() || shareDialog == null) {
|
|
|
+ dispatchError(requestId, "share", "ACTIVITY_UNAVAILABLE", "Android Activity 或分享对话框不可用。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final String url = params.optString("url", "").trim();
|
|
|
+ Uri uri = Uri.parse(url);
|
|
|
+ if (!"https".equalsIgnoreCase(uri.getScheme()) || uri.getHost() == null) {
|
|
|
+ dispatchError(requestId, "share", "INVALID_SHARE_URL", "Facebook 分享地址必须是有效的 HTTPS URL。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ShareLinkContent.Builder builder = new ShareLinkContent.Builder().setContentUrl(uri);
|
|
|
+ String quote = params.optString("quote", "").trim();
|
|
|
+ if (!quote.isEmpty()) builder.setQuote(quote);
|
|
|
+ String hashtag = params.optString("hashtag", "").trim();
|
|
|
+ if (!hashtag.isEmpty()) {
|
|
|
+ if (!hashtag.startsWith("#")) hashtag = "#" + hashtag;
|
|
|
+ builder.setShareHashtag(new ShareHashtag.Builder().setHashtag(hashtag).build());
|
|
|
+ }
|
|
|
+ final ShareLinkContent content = builder.build();
|
|
|
+ if (!shareDialog.canShow(content, ShareDialog.Mode.AUTOMATIC)) {
|
|
|
+ dispatchError(requestId, "share", "SHARE_UNAVAILABLE", "当前设备无法显示 Facebook 链接分享对话框。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ pendingShareRequestId = requestId;
|
|
|
+ activity.runOnUiThread(() -> {
|
|
|
+ try {
|
|
|
+ shareDialog.show(content, ShareDialog.Mode.AUTOMATIC);
|
|
|
+ } catch (Throwable error) {
|
|
|
+ pendingShareRequestId = null;
|
|
|
+ dispatchError(requestId, "share", "SHARE_START_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleLogEvent(String requestId, JSONObject params) {
|
|
|
+ runAppEventOnUiThread(requestId, "logEvent", () -> {
|
|
|
+ String eventName = params.optString("eventName", "").trim();
|
|
|
+ validateEventName(eventName);
|
|
|
+ Bundle eventParams = toEventBundle(params.optJSONObject("parameters"));
|
|
|
+ if (params.has("valueToSum") && !params.isNull("valueToSum")) {
|
|
|
+ appEventsLogger.logEvent(eventName, params.getDouble("valueToSum"), eventParams);
|
|
|
+ } else {
|
|
|
+ appEventsLogger.logEvent(eventName, eventParams);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleLogPurchase(String requestId, JSONObject params) {
|
|
|
+ runAppEventOnUiThread(requestId, "logPurchase", () -> {
|
|
|
+ Object amountValue = params.opt("amount");
|
|
|
+ if (!(amountValue instanceof Number)) {
|
|
|
+ throw new IllegalArgumentException("Facebook 购买事件 amount 必须是数字。");
|
|
|
+ }
|
|
|
+ BigDecimal amount = new BigDecimal(String.valueOf(amountValue));
|
|
|
+ if (amount.signum() < 0) {
|
|
|
+ throw new IllegalArgumentException("Facebook 购买事件 amount 不能小于 0。");
|
|
|
+ }
|
|
|
+ String currencyCode = params.optString("currency", "").trim().toUpperCase(Locale.US);
|
|
|
+ if (!currencyCode.matches("^[A-Z]{3}$")) {
|
|
|
+ throw new IllegalArgumentException("Facebook 购买事件 currency 必须是三位 ISO 4217 货币代码。");
|
|
|
+ }
|
|
|
+ Currency currency = Currency.getInstance(currencyCode);
|
|
|
+ Bundle eventParams = toEventBundle(params.optJSONObject("parameters"));
|
|
|
+ appEventsLogger.logPurchase(amount, currency, eventParams);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleFlushEvents(String requestId) {
|
|
|
+ runAppEventOnUiThread(requestId, "flushEvents", () -> appEventsLogger.flush());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void runAppEventOnUiThread(String requestId, String method, ThrowingRunnable action) {
|
|
|
+ final Activity activity = activityRef.get();
|
|
|
+ if (activity == null || activity.isFinishing() || appEventsLogger == null) {
|
|
|
+ dispatchError(requestId, method, "APP_EVENTS_UNAVAILABLE", "Facebook AppEventsLogger 不可用。");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ activity.runOnUiThread(() -> {
|
|
|
+ try {
|
|
|
+ action.run();
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ putQuietly(data, "accepted", true);
|
|
|
+ dispatchSuccess(requestId, method, false, data);
|
|
|
+ } catch (Throwable error) {
|
|
|
+ dispatchError(requestId, method, "APP_EVENT_ERROR", safeMessage(error));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Bundle toEventBundle(JSONObject parameters) throws JSONException {
|
|
|
+ Bundle bundle = new Bundle();
|
|
|
+ if (parameters == null) return bundle;
|
|
|
+ if (parameters.length() > MAX_EVENT_PARAMETERS) {
|
|
|
+ throw new IllegalArgumentException("Facebook 单个事件最多允许 25 个参数。");
|
|
|
+ }
|
|
|
+
|
|
|
+ Iterator<String> keys = parameters.keys();
|
|
|
+ while (keys.hasNext()) {
|
|
|
+ String key = keys.next();
|
|
|
+ validateEventName(key);
|
|
|
+ Object value = parameters.get(key);
|
|
|
+ if (value instanceof String) {
|
|
|
+ String stringValue = (String) value;
|
|
|
+ if (stringValue.length() > MAX_EVENT_PARAMETER_LENGTH) {
|
|
|
+ throw new IllegalArgumentException("Facebook 事件参数值不能超过 100 个字符:" + key);
|
|
|
+ }
|
|
|
+ bundle.putString(key, stringValue);
|
|
|
+ } else if (value instanceof Byte || value instanceof Short || value instanceof Integer || value instanceof Long) {
|
|
|
+ bundle.putLong(key, ((Number) value).longValue());
|
|
|
+ } else if (value instanceof Float || value instanceof Double) {
|
|
|
+ bundle.putDouble(key, ((Number) value).doubleValue());
|
|
|
+ } else {
|
|
|
+ throw new IllegalArgumentException("Facebook 事件参数只允许 string 或 number:" + key);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return bundle;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void validateEventName(String value) {
|
|
|
+ if (!EVENT_NAME_PATTERN.matcher(value).matches()) {
|
|
|
+ throw new IllegalArgumentException("Facebook 事件名和参数名必须为 2-40 位字母、数字、空格、_ 或 -。");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static List<String> parsePermissions(JSONArray values) {
|
|
|
+ List<String> permissions = new ArrayList<>();
|
|
|
+ if (values != null) {
|
|
|
+ for (int index = 0; index < values.length(); index++) {
|
|
|
+ String permission = values.optString(index, "").trim();
|
|
|
+ if (!permission.isEmpty() && !permissions.contains(permission)) {
|
|
|
+ permissions.add(permission);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (permissions.isEmpty()) {
|
|
|
+ permissions.add("public_profile");
|
|
|
+ permissions.add("email");
|
|
|
+ }
|
|
|
+ return permissions;
|
|
|
+ }
|
|
|
+
|
|
|
+ private synchronized String takePendingLoginRequestId() {
|
|
|
+ String requestId = pendingLoginRequestId;
|
|
|
+ pendingLoginRequestId = null;
|
|
|
+ return requestId;
|
|
|
+ }
|
|
|
+
|
|
|
+ private synchronized String takePendingShareRequestId() {
|
|
|
+ String requestId = pendingShareRequestId;
|
|
|
+ pendingShareRequestId = null;
|
|
|
+ return requestId;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void dispatchSuccess(String requestId, String method, boolean cancelled, JSONObject data) {
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+ putQuietly(response, "requestId", requestId);
|
|
|
+ putQuietly(response, "method", method);
|
|
|
+ putQuietly(response, "success", true);
|
|
|
+ putQuietly(response, "cancelled", cancelled);
|
|
|
+ putQuietly(response, "data", data == null ? new JSONObject() : data);
|
|
|
+ dispatchResponse(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void dispatchError(String requestId, String method, String code, String message) {
|
|
|
+ JSONObject error = new JSONObject();
|
|
|
+ putQuietly(error, "code", code);
|
|
|
+ putQuietly(error, "message", message);
|
|
|
+
|
|
|
+ JSONObject response = new JSONObject();
|
|
|
+ putQuietly(response, "requestId", requestId == null ? "" : requestId);
|
|
|
+ putQuietly(response, "method", method == null ? "unknown" : method);
|
|
|
+ putQuietly(response, "success", false);
|
|
|
+ putQuietly(response, "cancelled", false);
|
|
|
+ putQuietly(response, "error", error);
|
|
|
+ dispatchResponse(response);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void dispatchResponse(JSONObject response) {
|
|
|
+ final String payload = response.toString();
|
|
|
+ CocosHelper.runOnGameThread(
|
|
|
+ () -> JsbBridgeWrapper.getInstance().dispatchEventToScript(RESPONSE_EVENT, payload)
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void putQuietly(JSONObject object, String key, Object value) {
|
|
|
+ try {
|
|
|
+ object.put(key, value);
|
|
|
+ } catch (JSONException ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String safeMessage(Throwable error) {
|
|
|
+ if (error == null) return "未知错误";
|
|
|
+ String message = error.getMessage();
|
|
|
+ return message == null || message.trim().isEmpty()
|
|
|
+ ? error.getClass().getSimpleName()
|
|
|
+ : message;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
|
+ if (callbackManager != null) {
|
|
|
+ callbackManager.onActivityResult(requestCode, resultCode, data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDestroy() {
|
|
|
+ if (requestListener != null) {
|
|
|
+ JsbBridgeWrapper.getInstance().removeScriptEventListener(REQUEST_EVENT, requestListener);
|
|
|
+ requestListener = null;
|
|
|
+ }
|
|
|
+ if (callbackManager != null) {
|
|
|
+ LoginManager.getInstance().unregisterCallback(callbackManager);
|
|
|
+ }
|
|
|
+ pendingLoginRequestId = null;
|
|
|
+ pendingShareRequestId = null;
|
|
|
+ callbackManager = null;
|
|
|
+ shareDialog = null;
|
|
|
+ appEventsLogger = null;
|
|
|
+ activityRef.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ private interface ThrowingRunnable {
|
|
|
+ void run() throws Exception;
|
|
|
+ }
|
|
|
+}
|