ไม่สามารถเรียกใช้ dex: method ID ไม่ได้อยู่ใน [0, 0xffff]: 65536


344

ฉันเคยเห็นรุ่น dex erros มาก่อน แต่รุ่นนี้เป็นรุ่นใหม่ ทำความสะอาด / รีสตาร์ท ฯลฯ จะไม่ช่วย ดูเหมือนว่าโครงการห้องสมุดจะไม่บุบสลายและมีการเชื่อมโยงอย่างถูกต้อง

Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

หรือ

Cannot merge new index 65950 into a non-jumbo instruction

หรือ

java.util.concurrent.ExecutionException: com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536

tl; dr : ทางออกที่เป็นทางการจาก Google มาถึงแล้ว!

http://developer.android.com/tools/building/multidex.html

เคล็ดลับเล็ก ๆ เพียงข้อเดียวคุณอาจจำเป็นต้องทำเช่นนี้เพื่อป้องกันไม่ให้หน่วยความจำหมดเมื่อทำการทำ

dexOptions {
        javaMaxHeapSize "4g"
}

นอกจากนี้ยังมีโหมดจัมโบ้ที่สามารถแก้ไขได้ด้วยวิธีที่เชื่อถือได้น้อยกว่า:

dexOptions {
        jumboMode true
}

อัปเดต: หากแอปของคุณอ้วนและคุณมีหลายวิธีในแอพหลักของคุณคุณอาจต้องแอปของคุณอีกครั้งตาม

http://blog.osom.info/2014/12/too-many-methods-in-main-dex.html


1
คุณใช้ api ซึ่งไม่สามารถใช้งานได้บนอุปกรณ์ currient ของคุณหรือไม่?
rekire

มีเพราะโครงการอื่นสร้างปรับการกำหนดเป้าหมาย API รุ่นเดียวกัน
Edison

ดังนั้นคุณใช้ที่จุด API ซึ่งไม่สามารถใช้ได้? คุณตรวจสอบกับสายแบบif(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)ที่คุณไม่เรียกใช้ฟังก์ชั่นนี้หรือไม่ถ้ามันใช้งานไม่ได้?
rekire

ใช่ฉันทำ โครงการสร้างเสร็จก่อน นอกจากนี้ควรเป็นข้อผิดพลาดรันไทม์แม้ว่าฉันจะพลาดสาย
Edison

มันอาจจะเป็นหนึ่งในการอ้างอิงที่จะเลอะ (กำลังทำ maven + โครงการ lib อยู่ในขณะนี้)
Edison

คำตอบ:


379

อัปเดต 3 (2014/11/03)
Google เปิดตัวในที่สุดคำอธิบายอย่างเป็นทางการ


อัปเดต 2 (10/31/2557)
Gradle plugin v0.14.0 สำหรับ Android เพิ่มการรองรับสำหรับ multi-dex เพื่อเปิดใช้งานคุณต้องประกาศในbuild.gradle :

android {
   defaultConfig {
      ...
      multiDexEnabled  true
   }
}

หากแอปพลิเคชันของคุณรองรับ Android ก่อนหน้า 5.0 (นั่นคือถ้าคุณminSdkVersionอายุ 20 ปีหรือต่ำกว่า) คุณต้องแก้ไขแอปพลิเคชัน ClassLoaderแบบไดนามิกดังนั้นจะสามารถโหลดคลาสจาก dexes รองได้ โชคดีที่มีห้องสมุดที่เหมาะกับคุณ เพิ่มไปยังแอพของคุณ:

dependencies {
  ...
  compile 'com.android.support:multidex:1.0.0'
} 

คุณต้องเรียกใช้รหัสโปรแกรมแก้ไข ClassLoader โดยเร็วที่สุด เอกสารMultiDexApplicationของคลาสแนะนำวิธีการทำสามวิธี (เลือกหนึ่งวิธีที่สะดวกที่สุดสำหรับคุณ):

1 - ประกาศMultiDexApplicationคลาสเป็นแอปพลิเคชันในAndroidManifest.xmlของคุณ:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.multidex.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

2 - ให้ApplicationคลาสของคุณขยายคลาสMultiDexApplication :

public class MyApplication extends MultiDexApplication { .. }

3 - โทรMultiDex#installจากApplication#attachBaseContextวิธีการของคุณ:

public class MyApplication {
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
        ....
    }
    ....
}

อัปเดต 1 (10/17/2014):
ตามที่คาดการณ์ไว้การสนับสนุน multidexจะถูกจัดส่งในรุ่นที่ 21 ของห้องสมุดสนับสนุน Android คุณสามารถค้นหา android-support-multidex.jar ในโฟลเดอร์ / sdk / extras / android / support / multidex / library / libs


การสนับสนุนหลาย dex แก้ปัญหานี้ dx 1.8 อนุญาตให้สร้างไฟล์ dex หลายไฟล์ได้แล้ว
Android L จะรองรับหลาย dex และการแก้ไขไลบรารีการสนับสนุนครั้งต่อไปจะครอบคลุมรุ่นที่เก่ากว่ากลับไปที่ API 4

มันถูกระบุไว้ในนี้พอดคาสต์ตอนที่นักพัฒนาซอฟต์แวร์ Android เวทีโดยนายอันวาร์ Ghuloum ฉันโพสต์ข้อความการถอดเสียง (และคำอธิบายมัลติ - เด็กซ์ทั่วไป) ของส่วนที่เกี่ยวข้อง


2
โพสต์บล็อกเป็นโปรแกรมรักษา! : D
nadavfima

39
มีอะไรสำหรับผู้ใช้ eclipse หรือ
มูฮัมหมัดบาบาร์

52
@MuhammadBabar มีสตูดิโอ Android สำหรับผู้ใช้ Eclipse
VipulKumar

2
@ MohammedAli แน่นอนว่าหลีกเลี่ยงการใช้มันหากคุณสามารถ แต่สิ่งที่คุณควรทำอย่างไรถ้าคุณจริงๆมีวิธีการมากเกินไปใน app ของคุณและคุณพยายามแล้วเทคนิคทั้งหมดเช่นเดียวกับที่คุณกล่าวถึง? เกี่ยวกับเวลาในการสร้าง - มีวิธีแก้ปัญหาสำหรับเรื่องนี้อย่างน้อยสำหรับการสร้างการพัฒนา - ดูคำตอบของฉันที่นี่: stackoverflow.com/a/30799491/1233652
Alex Lipov

2
ใน Qt สำหรับ Android ฉันมีปัญหาที่รันไทม์สำหรับแอพของฉันเมื่อรวม SDK ของ Facebook + Twitter เข้าด้วยกันแม้หลังจากเปิดใช้งานการสนับสนุนมัลติidex (ข้อผิดพลาดข้อนี้ทำให้ฉันเป็นฝันร้ายโดยเฉพาะ: java.lang.ClassNotFoundException: Didn't find class "org.qtproject.qt5.android.QtActivityDelegate" on path: DexPathList[[],nativeLibraryDirectories=[/vendor/lib, /system/lib]] ) ปรากฏว่าข้อผิดพลาดของฉันคือฉันไม่ได้ใช้ขั้นตอนเพิ่มเติมสำหรับการสนับสนุน Android ก่อนหน้า 5.0 จากที่กล่าวมาตัวเลือก # 3 แก้ไขได้และฉันก็ไม่มีClassNotFoundExceptionปัญหาอีกแล้ว ขอบคุณ @Alex Lipov!
ปล้น

78

ตามที่ระบุไว้แล้วคุณมีวิธีการมากเกินไป (มากกว่า 65k) ในโครงการและ libs ของคุณ

ป้องกันปัญหา: ลดจำนวนวิธีด้วย Play Services 6.5+ และ support-v4 24.2+

เนื่องจากมักจะเป็นบริการ Google Play เป็นหนึ่งในผู้ต้องสงสัยหลักในวิธีการ "สูญเสีย" กับ20k + วิธี บริการ Google Play เวอร์ชัน 6.5 หรือใหม่กว่าเป็นไปได้ที่คุณจะรวมบริการ Google Play ในแอปพลิเคชันของคุณโดยใช้ไลบรารีไคลเอ็นต์ขนาดเล็กจำนวนหนึ่ง ตัวอย่างเช่นหากคุณต้องการเพียง GCM และแผนที่คุณสามารถเลือกใช้การอ้างอิงเหล่านี้เท่านั้น:

dependencies {
    compile 'com.google.android.gms:play-services-base:6.5.+'
    compile 'com.google.android.gms:play-services-maps:6.5.+'
}

รายการเต็มรูปแบบของห้องสมุดย่อยและความรับผิดชอบของมันสามารถพบได้ใน Google เอกสารอย่างเป็นทางการ

อัปเดต : ตั้งแต่ Support Library v4 v24.2.0 มันถูกแบ่งออกเป็นโมดูลต่อไปนี้:

support-compat, support-core-utils, support-core-ui, support-media-compatและsupport-fragment

dependencies {
    compile 'com.android.support:support-fragment:24.2.+'
}

อย่างไรก็ตามโปรดทราบหากคุณใช้support-fragmentมันจะมีการพึ่งพาโมดูลอื่น ๆ ทั้งหมด (เช่นถ้าคุณใช้android.support.v4.app.Fragmentไม่มีประโยชน์)

ดูที่นี่บันทึกย่อรุ่นอย่างเป็นทางการสำหรับ support-v4 lib


เปิดใช้งาน MultiDexing

ตั้งแต่ Lollipop (หรือที่รู้จักในการสร้างเครื่องมือ 21+) จึงง่ายต่อการจัดการ วิธีนี้คือการหลีกเลี่ยงวิธี 65k ต่อปัญหาไฟล์ dex เพื่อสร้างไฟล์ dex หลายไฟล์สำหรับแอปของคุณ เพิ่มสิ่งต่อไปนี้ในไฟล์ build gradle ของคุณ (ซึ่งนำมาจาก google doc อย่างเป็นทางการในแอปพลิเคชันที่มีมากกว่า 65k วิธี ):

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.0"

    defaultConfig {
        ...
        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

ขั้นตอนที่สองคือเตรียมคลาสแอปพลิเคชันของคุณหรือหากคุณไม่ขยายแอปพลิเคชันให้ใช้MultiDexApplicationในแอนดรอยด์ Android ของคุณ:

เพิ่มอย่างนี้ใน Application.java ของคุณ

@Override
  protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    MultiDex.install(this);
  }

หรือใช้แอปพลิเคชันที่ให้มาจาก mutlidex lib

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.myapplication">
    <application
        ...
        android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

ป้องกัน OutOfMemory ด้วย MultiDex

เป็นเคล็ดลับเพิ่มเติมหากคุณพบOutOfMemoryข้อยกเว้นในระหว่างขั้นตอนการสร้างคุณสามารถขยายกองด้วย

android {
    ...
    dexOptions {
        javaMaxHeapSize "4g"
    }
}

ซึ่งจะตั้งค่าฮีปเป็น 4 กิกะไบต์

ดูคำถามนี้สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับปัญหา dex heap memory


วิเคราะห์ที่มาของปัญหา

ในการวิเคราะห์แหล่งที่มาของวิธีการปลั๊กอิน gradle https://github.com/KeepSafe/dexcount-gradle-pluginสามารถช่วยในการรวมกันกับต้นไม้พึ่งพาที่จัดทำโดย gradle ด้วยเช่น

.\gradlew app:dependencies

ดูคำตอบและคำถามนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการนับใน Android


ฉันใช้โซลูชัน Play Services 6.5+ และทำงานได้อย่างสมบูรณ์ เคล็ดลับที่มีประโยชน์อย่างไม่น่าเชื่อ ขอบคุณมาก!
Hoang Nguyen Huu

ฉันจะถอนรากถอนโคนมากขึ้นถ้าทำได้ - ตัดการบริการ Play อื่น ๆ ทั้งหมดที่เราไม่ได้ใช้แก้ไขปัญหานี้โดยไม่ต้องหันไปใช้ multi-dex ซึ่งมีผลกระทบด้านลบเมื่อสร้าง
Sean Barbeau

1
มากกว่าที่คุณมีน้ำตาในดวงตาของฉัน คุณบันทึกฉัน
นอนไม่หลับ

ฉันใช้ไลบรารีไคลเอ็นต์สำหรับ GCM เพราะฉันใช้บริการ gcm เพียงอย่างเดียวจากบริการ play ตอนนี้มันแก้ไขปัญหาของฉันได้แล้ว ขอบคุณ! เพื่อประหยัดเวลาของฉัน
Ankit

57

โครงการของคุณใหญ่เกินไป คุณมีวิธีมากเกินไป สามารถมีได้เพียง 65536 วิธีต่อแอปพลิเคชัน ดูที่นี่https://code.google.com/p/android/issues/detail?id=7147#c6


ฉันเห็น. ฉันมีการอ้างอิงมากมายสำหรับโครงการนี้ มันสร้างได้ดีก่อนที่ฉันจะย้ายไปใช้ Maven แม้ว่า Maven อาจเพิ่มการพึ่งพาที่ไม่จำเป็น จะตรวจสอบอีกครั้ง
Edison

5
หากต้องการเฉพาะเจาะจงมากขึ้นจะต้องมี 65,536 วิธีต่อไฟล์ที่ปฏิบัติการได้ (dex) ของ Dalvik และแอปพลิเคชัน (APK) สามารถมีไฟล์ dex ได้มากกว่าหนึ่งไฟล์พร้อมการโหลดแบบกำหนดเอง
Dennis Sheil

7
มันเป็นข้อบกพร่องที่น่าอายจริงๆสำหรับ Android! อย่างไรก็ตามในกรณีที่ฉันลบ Jar ที่อยู่ใน libs และไม่ได้ใช้งานและแอพที่รวบรวม
David

เวลาทำความสะอาดโครงการของฉัน: /
Decoy

1
การแก้ไขอย่างรวดเร็วก็คือการใช้ Proguard ด้วยการสร้างการ
ซ่อมแซม

12

รหัสด้านล่างช่วยถ้าคุณใช้ Gradle ช่วยให้คุณสามารถลบบริการของ Google ที่ไม่จำเป็นออกได้อย่างง่ายดาย (สมมุติว่าคุณกำลังใช้อยู่) เพื่อให้ได้กลับต่ำกว่าเกณฑ์ 65k เครดิตทั้งหมดในโพสต์นี้: https://gist.github.com/dmarcato/d7c91b94214acd936e42

แก้ไข 2014-10-22 : มีการสนทนาที่น่าสนใจมากมายเกี่ยวกับส่วนสำคัญที่อ้างถึงข้างต้น TLDR? ดูที่นี่: https://gist.github.com/Takhion/10a37046b9e6d259bb31

วางรหัสนี้ที่ด้านล่างของไฟล์ build.gradle และปรับรายการบริการ google ที่คุณไม่ต้องการ:

def toCamelCase(String string) {
    String result = ""
    string.findAll("[^\\W]+") { String word ->
        result += word.capitalize()
    }
    return result
}

afterEvaluate { project ->
    Configuration runtimeConfiguration = project.configurations.getByName('compile')
    ResolutionResult resolution = runtimeConfiguration.incoming.resolutionResult
    // Forces resolve of configuration
    ModuleVersionIdentifier module = resolution.getAllComponents().find { it.moduleVersion.name.equals("play-services") }.moduleVersion

    String prepareTaskName = "prepare${toCamelCase("${module.group} ${module.name} ${module.version}")}Library"
    File playServiceRootFolder = project.tasks.find { it.name.equals(prepareTaskName) }.explodedDir

    Task stripPlayServices = project.tasks.create(name: 'stripPlayServices', group: "Strip") {
        inputs.files new File(playServiceRootFolder, "classes.jar")
        outputs.dir playServiceRootFolder
        description 'Strip useless packages from Google Play Services library to avoid reaching dex limit'

        doLast {
            copy {
                from(file(new File(playServiceRootFolder, "classes.jar")))
                into(file(playServiceRootFolder))
                rename { fileName ->
                    fileName = "classes_orig.jar"
                }
            }
            tasks.create(name: "stripPlayServices" + module.version, type: Jar) {
                destinationDir = playServiceRootFolder
                archiveName = "classes.jar"
                from(zipTree(new File(playServiceRootFolder, "classes_orig.jar"))) {
                    exclude "com/google/ads/**"
                    exclude "com/google/android/gms/analytics/**"
                    exclude "com/google/android/gms/games/**"
                    exclude "com/google/android/gms/plus/**"
                    exclude "com/google/android/gms/drive/**"
                    exclude "com/google/android/gms/ads/**"
                }
            }.execute()
            delete file(new File(playServiceRootFolder, "classes_orig.jar"))
        }
    }

    project.tasks.findAll { it.name.startsWith('prepare') && it.name.endsWith('Dependencies') }.each { Task task ->
        task.dependsOn stripPlayServices
    }
}

รักมัน! def ต้องการเนื่องจาก บริษัท เช่น Google ยังคงขยายแพคเกจ
เอดิสัน

1
นีซ - นี่เป็นงานที่ทำ ไม่ยุ่งยากและไม่ต้องกังวล!
slott

หมายเหตุ: ขวดบริการ google play ที่ถูกลบใน SDK Android ของฉันใน Android Studio! ความคิดที่ไม่ดีเนื่องจากไม่ใช่เรื่องง่ายที่จะเปลี่ยนกลับไปเป็นขวดดั้งเดิม ผู้เขียนควรแก้ไขสคริปต์เพื่อเปลี่ยนไหในไดเรกทอรีการสร้าง
ภายใน

@inder: ฉันไม่มีปัญหานั้น อย่างไรก็ตามฉันต้องทำcleanทุกครั้งที่ฉันแยกส่วนด้วยการยกเว้น (เราใช้การวิเคราะห์)
JohnnyLambada

จะแยกสิ่งนี้ออกจาก build build ได้อย่างไร?
user1324936

6

ฉันได้แชร์โครงการตัวอย่างที่แก้ปัญหานี้โดยใช้สคริปต์การสร้าง custom_rules.xml และโค้ดสองสามบรรทัด

ฉันใช้มันในโครงการของตัวเองและมันทำงานได้อย่างไร้ที่ติบนอุปกรณ์ 1M + (จาก android-8 ถึง android-19 ล่าสุด) หวังว่ามันจะช่วย

https://github.com/mmin18/Dex65536


1
ขอบคุณสำหรับสคริปต์ คุณควรระวัง ART อุปกรณ์อาจแปลงเฉพาะ dex เริ่มต้นของคุณและไม่ใช่อุปกรณ์รอง ควรใช้โซลูชัน Proguard
Edison

2
เมื่อฉันนำเข้าโครงการเข้าสู่ Eclipse และเรียกใช้มันจะให้ข้อผิดพลาด "ไม่สามารถเรียกใช้ dex: ID วิธีไม่ได้อยู่ใน [0, 0xffff]: 65536" คุณช่วยอธิบายการใช้งานของโครงการ
Karacago ได้ไหม

6

ประสบปัญหาเดียวกันและแก้ไขได้โดยการแก้ไขไฟล์ build.gradle ของฉันในส่วนการอ้างอิงโดยการลบ:

compile 'com.google.android.gms:play-services:7.8.0'

และแทนที่ด้วย:

compile 'com.google.android.gms:play-services-location:7.8.0'
compile 'com.google.android.gms:play-services-analytics:7.8.0' 

ที่สมบูรณ์แบบ! ฉันแค่ใช้ Google Drive API และใช้งานได้
vedavis

5

ลองเพิ่มรหัสด้านล่างใน build.gradle มันใช้งานได้สำหรับฉัน -

compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
    multiDexEnabled true
}

2

ทางออกที่สมบูรณ์แบบสำหรับสิ่งนี้คือการทำงานกับ Proguard ตามที่ aleb กล่าวถึงในความคิดเห็น มันจะลดขนาดของไฟล์ dex ลงครึ่งหนึ่ง


1
ตกลงที่มีขนาดใหญ่มากขึ้นบริการ Google Play ขวดโดยเฉพาะอย่างยิ่ง * (18k วิธีการด้วยตัวเอง)
เอดิสัน

2

คุณสามารถวิเคราะห์ปัญหา (การอ้างอิงไฟล์ dex) โดยใช้ Android Studio:

สร้าง -> วิเคราะห์ APK ..

บนแผงผลลัพธ์คลิกที่ไฟล์ classes.dex

และคุณจะเห็น:

ป้อนคำอธิบายรูปภาพที่นี่


0

gradle + โซลูชัน proguard:

afterEvaluate {
  tasks.each {
    if (it.name.startsWith('proguard')) {
        it.getInJarFilters().each { filter ->
            if (filter && filter['filter']) {
                filter['filter'] = filter['filter'] +
                        ',!.readme' +
                        ',!META-INF/LICENSE' +
                        ',!META-INF/LICENSE.txt' +
                        ',!META-INF/NOTICE' +
                        ',!META-INF/NOTICE.txt' +
                        ',!com/google/android/gms/ads/**' +
                        ',!com/google/android/gms/cast/**' +
                        ',!com/google/android/gms/games/**' +
                        ',!com/google/android/gms/drive/**' +
                        ',!com/google/android/gms/wallet/**' +
                        ',!com/google/android/gms/wearable/**' +
                        ',!com/google/android/gms/plus/**' +
                        ',!com/google/android/gms/topmanager/**'
            }
        }
    }
  }
}

0

ลบไฟล์ jar บางไฟล์ออกจากโฟลเดอร์ Libs และคัดลอกไปยังโฟลเดอร์อื่นและไปที่ _Project Properties> เลือก Java Build Path, เลือก Libraries, เลือก Add Jar ภายนอก, เลือก jar ที่ถูกลบไปยังโครงการของคุณ, คลิก save, จะถูกเพิ่มภายใต้การอ้างอิง ไลบรารีแทนโฟลเดอร์ Libs ตอนนี้ทำความสะอาดและเรียกใช้โครงการของคุณ คุณไม่จำเป็นต้องเพิ่มรหัสใด ๆ สำหรับ MultDex มันใช้งานได้ง่ายสำหรับฉัน


0

ฉันกำลังเผชิญกับปัญหาเดียวกันวันนี้สิ่งที่ทำงานด้านล่างอยู่

สำหรับ ANDROID STUDIO ... เปิดใช้งานการเรียกใช้ทันที

ในไฟล์ -> การตั้งค่า -> สร้างการดำเนินการปรับใช้ -> เรียกใช้ทันที -> เลือกเปิดใช้งานเรียกใช้ทันทีสำหรับ hot swap ...

หวังว่ามันจะช่วย


1
สิ่งนี้ใช้ได้กับฉัน - ฉันเพียงแค่ปิดการใช้งานเปิดใช้งานคลิกนำไปใช้เปิดใช้งานอีกครั้งและทำงานได้อีกครั้ง
MrBigglesworth
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.