Replugin 2.2.4 外掛化載入FacebookSDK出問題?這裡有解決方案

RoyGit發表於2018-03-10

我是一名外掛化愛好者,也是Replugin的鐵粉。

公司專案需要FacebookSDK,但是用Replugin進行外掛化載入,發現有Crash,花了點時間做了相容。有需要的同學可以看一下方案.

crash 關鍵字 1

Caused by: The SDK has not been initialized, make sure to call FacebookSdk.sdkInitialize() first.
複製程式碼

上面是因為,直接安裝外掛APK,facebook會被自動初始化。但是如果變成外掛,需要我們這邊手動初始化 程式碼如下:

        FacebookContextWrapper contextWrapper = new FacebookContextWrapper(this);
        FacebookSdk.setApplicationId("your id");
        FacebookSdk.sdkInitialize(contextWrapper, new FacebookSdk.InitializeCallback() {
            @Override
            public void onInitialized() {
            }
        });
複製程式碼

這裡用FacebookContextWrapper是為了避免出現資源訪問的問題,因為裡面會變成ApplicationContext,也就是宿主的context

public class FacebookContextWrapper extends ContextWrapper {

    public FacebookContextWrapper(Context base) {
        super(base);
    }
    //把這個方法重寫,返回是外掛的上下文
    @Override
    public Context getApplicationContext() {
        return super.getBaseContext();
    }
}

複製程式碼

crash 關鍵字 2

 Caused by: java.lang.VerifyError: Verifier rejected class com.facebook.AccessTokenManager:
 com.facebook.AccessTokenManager com.facebook.AccessTokenManager.getInstance() failed to verify:
 com.facebook.AccessTokenManager com.facebook.AccessTokenManager.getInstance(): [0x1A] register v2 has 
 type Reference: java.lang.Object but expected Precise Reference: 
 android.support.v4.content.LocalBroadcastManager (declaration of 'com.facebook.AccessTokenManager' 
 appears in /data/data/com.ostudio.issue.sdk/app_plugins_v3/login-10-10-1.jar:classes2.dex)
複製程式碼

校驗dex失敗了,首先我們先看看為什麼會失敗

我們將打好的包,使用apktool反編譯看一下smali ,定位到出問題的地方

.method static getInstance()Lcom/facebook/AccessTokenManager;
    .locals 4

    sget-object v0, Lcom/facebook/AccessTokenManager;->instance:Lcom/facebook/AccessTokenManager;

    if-nez v0, :cond_1

    const-class v1, Lcom/facebook/AccessTokenManager;

    monitor-enter v1

    :try_start_0
    sget-object v0, Lcom/facebook/AccessTokenManager;->instance:Lcom/facebook/AccessTokenManager;

    if-nez v0, :cond_0

    invoke-static {}, Lcom/facebook/FacebookSdk;->getApplicationContext()Landroid/content/Context;

    move-result-object v0

    //這句有問題

    invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance(Landroid/content/Context;)Ljava/lang/Object;

    move-result-object v0

    new-instance v2, Lcom/facebook/AccessTokenCache;

    invoke-direct {v2}, Lcom/facebook/AccessTokenCache;-><init>()V

    new-instance v3, Lcom/facebook/AccessTokenManager;

    invoke-direct {v3, v0, v2}, Lcom/facebook/AccessTokenManager;-><init>(Landroid/support/v4/content/LocalBroadcastManager;Lcom/facebook/AccessTokenCache;)V

    sput-object v3, Lcom/facebook/AccessTokenManager;->instance:Lcom/facebook/AccessTokenManager;

    :cond_0
    monitor-exit v1
    :try_end_0
    .catchall {:try_start_0 .. :try_end_0} :catchall_0

    :cond_1
    sget-object v0, Lcom/facebook/AccessTokenManager;->instance:Lcom/facebook/AccessTokenManager;

    return-object v0

    :catchall_0
    move-exception v0

    :try_start_1
    monitor-exit v1
    :try_end_1
    .catchall {:try_start_1 .. :try_end_1} :catchall_0

    throw v0
.end method
複製程式碼
    invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance(Landroid/content/Context;)Ljava/lang/Object;
複製程式碼

很明顯,這個單例的返回值應該是Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager型別,但是返回了Ljava/lang/Object;型別

所以應該改為

invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance(Landroid/content/Context;)Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;
複製程式碼

另一個地方也會觸發dex校驗的問題,就是Replugin外掛化只改掉了方法體內部的(LocalBroadcastManager改為PluginLocalBroadcastManager),但是有個全域性變數沒有改

.field private final localBroadcastManager:Landroid/support/v4/content/LocalBroadcastManager;
複製程式碼

所以這裡也要改為這個樣子

.field private final localBroadcastManager:Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;
複製程式碼

所以暫時建議大家先寫個指令碼,遍歷smali每一行程式碼,然後自動化修改

大概思路,就是生成外掛後->解壓外掛->使用baksmali將class.dex變為smali->自動化修改smali->壓縮apk

//程式碼寫的不好,見諒
public class FacebookDealLine implements IDealLine {
    @Override
    public String deal(String line, String fileNme) {
        if (fileNme.contains("facebook")) {
            if (line.contains("Landroid/support/v4/content/LocalBroadcastManager;")) {
//                System.out.print(fileNme);
                line = line.replace("Landroid/support/v4/content/LocalBroadcastManager;", "Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;");
            }
            if (line.contains("invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance(Landroid/content/Context;)Ljava/lang/Object;")) {
                line = line.replace("invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance(Landroid/content/Context;)" +
                        "Ljava/lang/Object;", "invoke-static {v0}, Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;->getInstance" +
                        "(Landroid/content/Context;)Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;");
            }
        } else if (fileNme.contains("PluginLocalBroadcastManager")) {
            if (line.contains(".method public static getInstance(Landroid/content/Context;)Ljava/lang/Object;")) {
                line = line.replace(".method public static getInstance(Landroid/content/Context;)Ljava/lang/Object;", ".method public static getInstance" +
                        "(Landroid/content/Context;)Lcom/qihoo360/replugin/loader/b/PluginLocalBroadcastManager;");
            }
        }
        return line;
    }
}
複製程式碼

按上面幾步操作完,還會有些問題

crash 關鍵字 3

      java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
                      at com.facebook.FacebookSdk.getAutoLogAppEventsEnabled(Unknown Source:5)
                      at com.facebook.appevents.internal.AutomaticAnalyticsLogger.logActivateAppEvent(Unknown Source:8)
                      at com.facebook.internal.FetchedAppSettingsManager$1.run(Unknown Source:64)
                      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
                      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
                      at java.lang.Thread.run(Thread.java:784)
複製程式碼

報Facebook內部空指標了,看原始碼

    public static boolean getAutoLogAppEventsEnabled() {
        Validate.sdkInitialized();
        return autoLogAppEventsEnabled;
    }
複製程式碼

返回的autoLogAppEventsEnabled為空,那我們找到定義的地方

        if (autoLogAppEventsEnabled == null) {
            autoLogAppEventsEnabled = ai.metaData.getBoolean(
                AUTO_LOG_APP_EVENTS_ENABLED_PROPERTY,
                true);
        }
複製程式碼

OK,很明顯,是從metadata中取值,改的方法很多,簡單點直接在宿主的mainfest中新增

        <meta-data
            android:name="com.facebook.sdk.AutoLogAppEventsEnabled"
            android:value="true"/>
複製程式碼

或者如果你是更新外掛的話,可以直接在facebook的原始碼中修改位元組碼,來解決這個問題。

最終經過很多次改動

D/cql: 初始化成功

相關文章