Преместване на класове към multidex в съществуващ APK

Опитвам се да преместя някои рамки от classes.dex към classes2.dex (MultiDex) от съществуващ APK. За целта използвам smali. Изглежда, че работи за някои приложения, а за някои не:

D/dalvikvm( 1401): GC_CONCURRENT freed 258K, 24% free 13896K/18268K, paused 2ms+1ms, total 19ms
I/dalvikvm( 2737): Could not find method com.facebook.FacebookSdk.sdkInitialize, referenced from method com.foursquare.robin.App.onCreate
W/dalvikvm( 2737): VFY: unable to resolve static method 16788: Lcom/facebook/FacebookSdk;.sdkInitialize (Landroid/content/Context;)V
D/dalvikvm( 2737): VFY: replacing opcode 0x71 at 0x014d
E/dalvikvm( 2737): Could not find class 'com.twitter.sdk.android.core.u', referenced from method com.foursquare.common.app.support.am.a
W/dalvikvm( 2737): VFY: unable to resolve new-instance 8004 (Lcom/twitter/sdk/android/core/u;) in Lcom/foursquare/common/app/support/am;
D/dalvikvm( 2737): VFY: replacing opcode 0x22 at 0x0005
D/dalvikvm( 2737): DexOpt: unable to opt direct call 0xd553 at 0x09 in Lcom/foursquare/common/app/support/am;.a
I/MultiDex( 2737): VM with version 1.6.0 does not have multidex support
I/MultiDex( 2737): install
I/MultiDex( 2737): MultiDexExtractor.load(/data/app/com.foursquare.robin-1.apk, false)
I/MultiDex( 2737): Detected that extraction must be performed.
D/dalvikvm( 2737): GC_CONCURRENT freed 325K, 11% free 3389K/3784K, paused 1ms+0ms, total 5ms
I/MultiDex( 2737): Extraction is needed for file /data/data/com.foursquare.robin/code_cache/secondary-dexes/com.foursquare.robin-1.apk.classes2.zip
I/MultiDex( 2737): Extracting /data/data/com.foursquare.robin/code_cache/secondary-dexes/com.foursquare.robin-1.apk.classes-838392451.zip
I/MultiDex( 2737): Renaming to /data/data/com.foursquare.robin/code_cache/secondary-dexes/com.foursquare.robin-1.apk.classes2.zip
I/MultiDex( 2737): Extraction success - length /data/data/com.foursquare.robin/code_cache/secondary-dexes/com.foursquare.robin-1.apk.classes2.zip: 392940
I/MultiDex( 2737): load found 1 secondary dex files
D/dalvikvm( 2737): DexOpt: --- BEGIN 'com.foursquare.robin-1.apk.classes2.zip' (bootstrap=0) ---
I/dalvikvm( 2753): No library specified. The standard exception handler will be used
D/dalvikvm( 2753): DexOpt: load 18ms, verify+opt 57ms, 1428508 bytes
D/dalvikvm( 2737): DexOpt: --- END 'com.foursquare.robin-1.apk.classes2.zip' (success) ---
D/dalvikvm( 2737): DEX prep '/data/data/com.foursquare.robin/code_cache/secondary-dexes/com.foursquare.robin-1.apk.classes2.zip': unzip in 13ms, rewrite 232ms
I/MultiDex( 2737): install done
D/AndroidRuntime( 2737): Shutting down VM
W/dalvikvm( 2737): threadid=1: thread exiting with uncaught exception (group=0x42d5d140)
E/AndroidRuntime( 2737): FATAL EXCEPTION: main
E/AndroidRuntime( 2737): Process: com.foursquare.robin, PID: 2737
E/AndroidRuntime( 2737): java.lang.NoClassDefFoundError: com.twitter.sdk.android.core.u
E/AndroidRuntime( 2737):    at com.foursquare.common.app.support.am.a(SourceFile)
E/AndroidRuntime( 2737):    at com.foursquare.robin.App.onCreate(SourceFile:213)
E/AndroidRuntime( 2737):    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
E/AndroidRuntime( 2737):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344)
E/AndroidRuntime( 2737):    at android.app.ActivityThread.access$1500(ActivityThread.java:135)
E/AndroidRuntime( 2737):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
E/AndroidRuntime( 2737):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 2737):    at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime( 2737):    at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime( 2737):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2737):    at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 2737):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime( 2737):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime( 2737):    at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager( 1321):   Force finishing activity com.foursquare.robin/.activities.MainActivity

Това ли е защото MultiDex е инсталиран след API на Twitter или трябва да модифицирам нещо друго освен dex файловете?


person joe-jeff    schedule 11.09.2015    source източник


Отговори (1)


Първо ще цитирам себе си (от тази публикация в блога):

И така, какво е main dex и кои класове трябва да включва?

При стартиране на приложението ClassLoader по подразбиране има един запис в своя път - файл classes.dex. Нарича се още главен декс. За да поддържа повече от един dex файл, библиотеката за поддръжка на multidex внедри корекция по време на изпълнение на пътя на ClassLoader. Този код трябва да се изпълнява веднага щом имате контекста на приложението (перфектното място за него е в метод Application#attachBaseContext).

Следователно класът Application трябва определено да бъде включен в главния dex, тъй като вече трябва да присъства, когато правите корекции на ClassLoader.

Трябва ли да се включат други класове? да Има нещо, наречено Dalvik верификатор, което има сложни правила за определяне на неподходящ байт код. Например, преди да зареди класа Application, VM верификаторът извършва своите проверки и ако намери поле, чийто тип не може да разреши (все още), няма да позволи изпълнението на инструкция за достъп до това поле, дори ако в този момент вече сме закърпили ClassLoader и класът може да бъде разрешен.

Във вашия пример класът Application на приложението (com.foursquare.robin.App) косвено зависи от класа com.twitter.sdk.android.core.u. Но както можете да видите във вашите регистрационни файлове, Dalvik верификаторът вече е закърпил инструкцията за нов екземпляр:

E/dalvikvm( 2737): Could not find class 'com.twitter.sdk.android.core.u', referenced from method com.foursquare.common.app.support.am.a
W/dalvikvm( 2737): VFY: unable to resolve new-instance 8004 (Lcom/twitter/sdk/android/core/u;) in Lcom/foursquare/common/app/support/am;
D/dalvikvm( 2737): VFY: replacing opcode 0x22 at 0x0005 
person Alex Lipov    schedule 11.09.2015
comment
Хм, това, което не разбирам, е как ще работи multi-dex, ако може да включва само класове, които не са посочени (директно или индиректно) от основното приложение? Тъй като основното приложение е входната точка, то препраща към всичко. - person joe-jeff; 11.09.2015
comment
Не, не е. Например, обикновено класът Application не препраща към класове Activity и/или Service. - person Alex Lipov; 11.09.2015
comment
Въпреки това според вашия блог всички класове за дейност/услуги са основни класове и всички препратки трябва да са в главния dex, нали? Та се чудя какво да сложа във 2-ри dex? - person joe-jeff; 11.09.2015
comment
Ето как е конфигуриран плъгинът gradle - той наистина третира всеки компонент като корен за изчисляване на графиката на основните dex класове. Въпреки това от моя опит, всички компоненти (с изключение на приложението) могат да бъдат преместени във вторични индекси (стига да не се препращат от класа на приложението и неговите зависимости). - person Alex Lipov; 11.09.2015