我是一名外掛化愛好者,也是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: 初始化成功