6

I have an app built with react native and I need to enable MultiDexsupport. My problem is that I can't import the MultiDexApplication class to extend it because at compile time I get symbol not found error for both the import statement and the class name when extending it in MainApplication.java

build.gradle

    dependencies {
        classpath('com.android.tools.build:gradle:3.5.3')
        classpath 'com.google.gms:google-services:4.2.0'
        classpath "androidx.multidex:multidex:2.0.1"

    }

If I try to add the dependency as implementation, I get the following error when starting the app:

Could not find method implementation() for arguments [androidx.multidex:multidex:2.0.1] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.

In all online resources I saw that the dependecy was added as implementation so I guess that can be my problem.

MainApplication.java

package com.classmanager;

import android.app.Application;
import androidx.multidex.MultiDexApplication;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.oblador.vectoricons.VectorIconsPackage;
import com.oblador.vectoricons.VectorIconsPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class MainApplication extends MultiDexApplication  implements ReactApplication {
  private final ReactNativeHost mReactNativeHost =
      new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this); // Remove this line if you don't want Flipper enabled
  }

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

  /**
   * Loads Flipper in React Native templates.
   *
   * @param context
   */
  private static void initializeFlipper(Context context) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
        aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }
}

It's the default MainApplication from react-native init, except that I imported the MultiDexApplication class and extended it instead of Application. But when I run the app, I get the following error:

    import androidx.multidex.MultiDexApplication;
                        ^
  symbol:   class MultiDexApplication
  location: package androidx.multidex
C:\Users\meadi\WebstormProjects\ClassManager\android\app\src\main\java\com\classmanager\MainApplication.java:16: error: cannot find symbol
public class MainApplication extends MultiDexApplication  implements ReactApplication {
                                     ^
  symbol: class MultiDexApplication
C:\Users\meadi\WebstormProjects\ClassManager\android\app\src\main\java\com\classmanager\MainApplication.java:18: error: incompatible types: MainApplication cannot be converted to Application
      new ReactNativeHost(this) {
                          ^

Any idea why MultiDexApplication couldn't be resolved?

update: I tried adding the multidex dependecy as implementation to the app level build.gradle. It seems now that the class is resolved, but i get this error:

    D8: Cannot fit requested classes in a single dex file (# methods: 100718 > 65536)
com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives:
The number of method references in a .dex file cannot exceed 64K.

So MultiDex is still not enabled

Update: Here is the project level build.gradle

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    ext {
        buildToolsVersion = "28.0.3"
        minSdkVersion = 16
        compileSdkVersion = 28
        targetSdkVersion = 28
         multiDexEnabled = true
    }
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath('com.android.tools.build:gradle:3.5.3')
        classpath 'com.google.gms:google-services:4.2.0'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        mavenLocal()
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
            url("$rootDir/../node_modules/react-native/android")
        }
        maven {
            // Android JSC is installed from npm
            url("$rootDir/../node_modules/jsc-android/dist")
        }

        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

And here is the app level build.gradle

apply plugin: "com.android.application"

import com.android.build.OutputFile

project.ext.react = [
        entryFile   : "index.js",
        enableHermes: false,  // clean and rebuild if changing
]

apply from: "../../node_modules/react-native/react.gradle"

/**
 * Set this to true to create two separate APKs instead of one:
 *   - An APK that only works on ARM devices
 *   - An APK that only works on x86 devices
 * The advantage is the size of the APK is reduced by about 4MB.
 * Upload all the APKs to the Play Store and people will download
 * the correct one based on the CPU architecture of their device.
 */
def enableSeparateBuildPerCPUArchitecture = false

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = false

/**
 * The preferred build flavor of JavaScriptCore.
 *
 * For example, to use the international variant, you can use:
 * `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
 *
 * The international variant includes ICU i18n library and necessary data
 * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
 * give correct results when using with locales other than en-US.  Note that
 * this variant is about 6MiB larger per architecture than default.
 */
def jscFlavor = 'org.webkit:android-jsc:+'

/**
 * Whether to enable the Hermes VM.
 *
 * This should be set on project.ext.react and mirrored here.  If it is not set
 * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
 * and the benefits of using Hermes will therefore be sharply reduced.
 */
def enableHermes = project.ext.react.get("enableHermes", false);

android {
    compileSdkVersion rootProject.ext.compileSdkVersion

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    defaultConfig {
        applicationId "com.classmanager"
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode 1
        versionName "1.0"
    }
    splits {
        abi {
            reset()
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false  // If true, also generate a universal APK
            include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
        }
    }
    signingConfigs {
        debug {
            storeFile file('debug.keystore')
            storePassword 'android'
            keyAlias 'androiddebugkey'
            keyPassword 'android'
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }
        release {
            // Caution! In production, you need to generate your own keystore file.
            // see https://facebook.github.io/react-native/docs/signed-apk-android.
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
    // applicationVariants are e.g. debug, release
    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // For each separate APK per architecture, set a unique version code as described here:
            // https://developer.android.com/studio/build/configure-apk-splits.html
            def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
            def abi = output.getFilter(OutputFile.ABI)
            if (abi != null) {  // null for the universal-debug, universal-release variants
                output.versionCodeOverride =
                        versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
            }

        }
    }
}

dependencies {

    implementation project (':react-native-vector-icons')
    implementation 'com.google.firebase:firebase-analytics:17.2.0'
    implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha02'
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation "com.facebook.react:react-native:+"  // From node_modules

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
}

// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
    from configurations.compile
    into 'libs'
}

apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply plugin: 'com.google.gms.google-services'
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
Adrian Pascu
  • 949
  • 5
  • 20
  • 48
  • Isn't is should be `implementation 'com.android.support:multidex:2.0.1' Also dependencies should be in app level gradle .. I have no idea about ReatNative though ` – ADM Dec 28 '19 at 13:26
  • Let me check. I don;t think i tried with the androidx version in the app level build.gradle – Adrian Pascu Dec 28 '19 at 13:33

2 Answers2

9

classpath "androidx.multidex:multidex:2.0.1". It should be implementation 'androidx.multidex:multidex:2.0.1'.

build.gradle (Module)-> This defines the module-specific build configurations.

build.gradle (Project)-> This defines your build configuration that apply to all modules. This file is integral to the project, so you should maintain them in revision control with all other source code.

You should add below Module Level build.gradle (android/app/build.gradle) section.

dependencies {

    implementation 'androidx.multidex:multidex:2.0.1'
}

FYI

Please remove multiDexEnabled = true from project level build.gradle section

Modify the module-level build.gradle file to enable multidex and add the multidex library as a dependency, as shown here:

android {
    defaultConfig {
    applicationId "com.classmanager"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 1
    versionName "1.0"
    multiDexEnabled true
    }

}
IntelliJ Amiya
  • 74,896
  • 15
  • 165
  • 198
  • I have added this dependency in the module level `build.gradle` and removed the on in the app level. Double checked that in the app level `build.gradle` I have `multiDexEnabled true`. After doing that, when runing `npx react-native run-android` I get this error while building `Execution failed for task ':app:mergeDexDebug'. > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade > com.android.builder.dexing.DexArchiveMergerException: Error while merging dex archives: The number of method references in a .dex file cannot exceed 64K. ` – Adrian Pascu Dec 31 '19 at 09:15
  • @AdrianPascu kindly share build.gradle please – IntelliJ Amiya Dec 31 '19 at 09:53
  • check is there any old (version) dependencies present or not? and add `dexOptions { javaMaxHeapSize "4g" }` – IntelliJ Amiya Dec 31 '19 at 09:56
  • Updated the post with build.gradle – Adrian Pascu Dec 31 '19 at 10:13
  • And where should I be adding that option? – Adrian Pascu Dec 31 '19 at 10:14
  • @AdrianPascu within `android { }` block. Module level build.gradle – IntelliJ Amiya Dec 31 '19 at 10:54
  • `buildToolsVersion = "29.0.2" minSdkVersion = 16 compileSdkVersion = 29 targetSdkVersion = 29` – IntelliJ Amiya Dec 31 '19 at 11:00
  • gradle wrapper `distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip` ? – IntelliJ Amiya Dec 31 '19 at 11:04
  • Added `dexOptions` and changed the buildTarget, still the same error regarding the 64k limit. Also, my gradle wrapper is 5.5 – Adrian Pascu Dec 31 '19 at 11:41
0

Have you added this to your app level build.gradle ?

android {
    defaultConfig {
        ...
        minSdkVersion ... 
        targetSdkVersion ...
        multiDexEnabled true // <------------------------
    }
    ...
}

(Reference from https://developer.android.com/studio/build/multidex#mdex-gradle)

Sean
  • 5,176
  • 2
  • 34
  • 50
  • Yes,I have added it – Adrian Pascu Dec 30 '19 at 17:13
  • Reading all the communications above, I believe the library import is fixed (the `implementation`). now, it seems like gradle fails to kick in and handle the multidex. Maybe you're using an old version of gradle plugin? Maybe you misplaced the `multiDexEnabled `? Maybe it's worth posting the whole build.gradle – Sean Dec 31 '19 at 10:02