Перемещение классов в мультидекс в существующем APK

Я пытаюсь переместить некоторые фреймворки из class.dex в class2.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 устанавливается после Twitter API, или мне нужно изменить что-то еще, кроме файлов dex?


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


Ответы (1)


Сначала я процитирую себя (из этот пост в блоге< /а>):

Так что же такое main dex и какие классы он должен включать?

При запуске приложения ClassLoader по умолчанию имеет единственную запись в своем пути — файл class.dex. Его еще называют основным dex. Для поддержки более одного файла dex в библиотеке поддержки multidex реализовано исправление пути ClassLoader во время выполнения. Этот код должен выполняться, как только вы получите контекст приложения (идеальное место для него — Application#attachBaseContext).

Поэтому класс Application обязательно должен быть включен в основной декс, так как он уже должен присутствовать при патче ClassLoader.

Любые другие классы должны быть включены? Да. Существует вещь под названием Dalvik Verifier, которая имеет сложные правила для определение неподходящего байт-кода. Например, перед загрузкой класса Application VM verifier выполняет свои проверки и, если находит поле, тип которого не может разрешить (пока), не разрешает выполнение инструкции, обращающейся к этому полю, даже если в этот момент мы уже исправили ClassLoader, и класс можно было разрешить.

В вашем примере класс приложения (com.foursquare.robin.App) косвенно зависит от класса com.twitter.sdk.android.core.u. Но, как вы можете видеть в ваших логах, Dalvik Verifier уже исправил инструкцию нового экземпляра:

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
Нет, это не так. Например, обычно класс приложения не ссылается ни на какие классы действий и/или служб. - person Alex Lipov; 11.09.2015
comment
Однако, согласно вашему блогу, все классы деятельности/сервисов являются корневыми классами, и все ссылки должны быть в основном каталоге, верно? Вот мне и интересно, что мне поставить во 2-й dex? - person joe-jeff; 11.09.2015
comment
Вот как настроен плагин Gradle — он действительно рассматривает каждый компонент как корень для расчета графа классов main-dex. Однако, по моему опыту, все компоненты (кроме приложения) могут быть перемещены во вторичные индексы (если на них не ссылаются из класса приложения и его зависимостей). - person Alex Lipov; 11.09.2015