How do I enable multidex for react native? - java

I'm pretty sure its a built in feature but I cant find anything when searching or in the docs. Is there a flag for building with multidex enabled?
On another note:
Any way to see which libraries are messing with your method count? Hitting the 64k limit came as quite a surprise.

For RN 0.59+ and using Gradle 3.4.1, none of the answers here had the complete solution. I did the following and it worked:
In android/app/build.gradle, update the dependency block:
dependencies {
// ... your other dependencies
// Multidex
implementation 'com.android.support:multidex:1.0.3'
}
And also update the defaultConfig in the android block:
defaultConfig {
// ... your `applicationId`, etc.
multiDexEnabled true
}
In MainApplication.java, replace
import android.app.Application;
at the top with
import android.support.multidex.MultiDexApplication;
OR if you're on RN 0.60+ or have manually upgraded to AndroidX then use this instead:
import androidx.multidex.MultiDexApplication;
Still in MainApplication.java, replace
public class MainApplication extends Application implements ReactApplication {
with
public class MainApplication extends MultiDexApplication implements ReactApplication {

Found the answer somewhere else. It's no different than enabling it for any regular Android project.
android {
....
defaultConfig {
...
multiDexEnabled true
}
As for method count, this site does the trick: http://inloop.github.io/apk-method-count/

android/app/build.gradle
android {
....
defaultConfig {
...
multiDexEnabled true
}
If you are using Multidex, your Application should extends MultiDexApplication instead of Application.
MyApplication.java
import android.support.multidex.MultiDexApplication;
public class MyApplication extends MultiDexApplication{
...
}

Since Application must extend ReactApplication, I used a similar approach to the one suggested here which is documented in point 2 in the Android Developer reference on multidex to attach to the base context:
app/build.gradle
android {
compileSdkVersion projectCompileSdkVersion // Or your version
defaultConfig {
minSdkVersion projectMinSdkVersion // Or your version
targetSdkVersion projectTargetSdkVersion // Or your version
multiDexEnabled true // *
}
dexOptions {
jumboMode true // *
}
}
dependencies {
compile 'com.android.support:multidex:1.0.3' // https://mvnrepository.com/artifact/com.android.support/multidex
}
MainApplication.java
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}

However, if your minSdkVersion is set to 20 or lower, then you must use the multidex support library as follows:
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 26
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.3'
}
https://developer.android.com/studio/build/multidex

Step:1
Open the /android/app/build.gradle
android {
...
defaultConfig {
...
multiDexEnabled true <-- ADD THIS LINE
}
}
Step:2
In the same file find dependencies
dependencies {
...
implementation 'androidx.multidex:multidex:2.0.1' <-- ADD THIS LINE
...
}
Note: To know latest version for multidex Multidex Latest Version
Step:3
Open the MainApplication.java file under
android/app/src/main/java/.../MainApplication.java
Add the multidex Import
// ... all your other imports here
import androidx.multidex.MultiDexApplication; <-- ADD THIS LINE
Our class definition needs extends MultiDexApplication like below
Beofre (In my case)
public class MainApplication extends Application implements ReactApplication {
After
public class MainApplication extends MultiDexApplication implements ReactApplication {
Replace Application with MultiDexApplication
Spet:4 (Optional)
clean the project
Reference How To Enable Multidex in Android
Hope this helps ;)

Related

No static method decodeBase64 - Google Credential

I built an Android application with a service account on it to upload files on Google Drive, which works perfectly on the emulator and Android Nougat. Now, I tried it on a Samsung Galaxy Tab A with Android 8.1 and before implementing the service account everything worked fine. Now, when I try to save a file on google Drive from it, I get the error:
java.lang.NoSuchMethodError: No static method decodeBase64(Ljava/lang/String;)[B in class Lorg/apache/commons/codec/binary/Base64; or its super classes (declaration of 'org.apache.commons.codec.binary.Base64' appears in /system/framework/org.apache.http.legacy.boot.jar)
The problematic code is where I log in, in particular in the fromStream method:
private Credential authorize () throws IOException {
InputStream in = getAssets().open("credentials.json");
return GoogleCredential.fromStream(in)
.createScoped(Collections.singleton(DriveScopes.DRIVE_FILE));
}
These are the new libraries implemented, I add commons-codec:commons-codec:1.15 since I read that it can be caused by it but it still doesn't work:
//API Google Drive
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
exclude module: 'guava-jdk5'
}
// https://mvnrepository.com/artifact/com.google.apis/google-api-services-drive
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') {
exclude group: 'org.apache.httpcomponents'
exclude module: 'guava-jdk5'
}
implementation 'com.google.http-client:google-http-client-gson:1.26.0'
implementation 'commons-codec:commons-codec:1.15'
How can I solve it?
Edit: these are the only apaches' libraries that I used in the whole project, but they have been used to write the .xlsx file in local and never gave me any kind of problem on the Galaxt Tab A before implementing the service credentials:
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
This is a known issue with the version of google-api-client-android you're using. The solution is to upgrade the version from 1.26 to 1.28 (or downgrade it to 1.25, see this comment).
I was able to reproduce the issue using an Empty Activity project and a virtual device with an API Level 26 and a Target Android 8.0 (Google APIs)
Build.gradle content :
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
useProguard false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.gms:play-services-auth:19.0.0'
//changing the version here from 1.26.0 to 1.28.0 resolves the issue
implementation('com.google.api-client:google-api-client-android:1.26.0') {
exclude group: 'org.apache.httpcomponents'
exclude module: 'guava-jdk5'
}
implementation('com.google.apis:google-api-services-drive:v3-rev136-1.25.0') {
exclude group: 'org.apache.httpcomponents'
exclude module: 'guava-jdk5'
}
implementation 'commons-codec:commons-codec:1.15'
}
MainActivity.java content:
package com.example.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.services.drive.DriveScopes;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
authorize();
} catch (Exception e) {
e.printStackTrace();
}
}
private Credential authorize () throws IOException {
InputStream in = getAssets().open("credentials.json");
return GoogleCredential.fromStream(in)
.createScoped(Collections.singleton(DriveScopes.DRIVE_FILE));
}
}

Could not find method implementation() for arguments [directory 'libs'] on object

Error Message:- Could not find method implementation() for arguments [directory
'libs'] on object of type
org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
Code
apply plugin: 'com.android.application'
ext {
supportVersion='27.1.1'
}
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.eassycars.www.dlservices"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildscript {
repositories {
jcenter()
}
configure(':app') {
dependencies {
classpath 'com.android.tools.build.gradle:4.8.1'
implementation fileTree (include: ['*.jar'], dir: 'libs')
implementation "com.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler :$supportVersion"
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation "com.android.support:cardview-v7:$supportVersion"
implementation "com.android.support:recyclerview-v7:$supportVersion"
implementation "com.android.support:design:$supportVersion"
implementation "com.android.support:palette-v7:$supportVersion"
implementation "com.android.support:customtabs:$supportVersion"
implementation "com.android.support:support-v4:$supportVersion"
implementation 'com.google.android.exoplayer:exoplayer:r2.0.4'
// utils
implementation 'com.github.bumptech.glide:glide:4.0.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0'
implementation 'com.koushikdutta.ion:ion:2.1.7'
implementation 'com.github.Commit451:bypasses:1.0.4'
implementation 'com.jakewharton:butterknife:8.8.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.0'
implementation 'com.drewnoakes:metadata-extractor:2.9.1'
implementation 'com.orhanobut:hawk:2.0.1'
classpath 'com.google.gms:google-services:3.1.1'
implementation 'com.android.support:support-annotations:27.1.1'
}}
}
}
I updated the "distributionUrl in my "gradle/wrapper/gradle-wrapper.properties" file to match the current gradle version.
I also updated the classpath in my top level build.gradle file to match the gradle API level.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
}
}
Re-synced and then it built OK.
Because you have incorrect block in your build.gradle. Looks like you're mixing top level build.gradle and module build.gradle. Your app module build.gradle should be something like this:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion '27.0.3'
defaultConfig {
...
}
buildTypes {
release {
...
}
}
..
}
dependencies {
...
}
please visit Configure your build for details.
Remove the space between version:
implementation "com.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler:$supportVersion"
Also, please move the dependencies block out of the android block:
android {
...
}
...
dependencies{
...
}

getSupportFragmentManager().getFragments() shows a compile time error

Calling getSupportFragmentManager().getFragments() shows a compile time error with the message below:
getSupportFragmentManager().getFragments() can only be called from
within the same library group(groupId = com.android.support)
I have imported the following classes in MainActivity:
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.widget.Toast;
MainActivity extends AppCompatActivity.
My project module level build.gradle file is as follows:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId "com.mycompany.floatingdemo"
minSdkVersion 16
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:design:25.2.0'
compile 'com.android.support:support-vector-drawable:25.2.0'
testCompile 'junit:junit:4.12'
}
This is the source code for the method getFragments inside FragmentManager.java.
/**
* Get a list of all fragments that have been added to the fragment manager.
*
* #return The list of all fragments or null if none.
* #hide
*/
#RestrictTo(LIBRARY_GROUP)
public abstract List<Fragment> getFragments();
I have recently updated my Android Studio to the latest stable version (2.3) and updated the Android Gradle plugin as well. I think this may be relevant because I have not previously seen this error.
As noticeable in the FragmentManager documentation, getFragments() is not a public method available to apps, but an internal implementation detail of the Support Library, hence the use of the RestrictTo annotation that was added to prevent usage of private APIs.
You'll want to change your code to not use getFragments and only use the public APIs.
Alternative For those who may be using getFragments() in their coding, I have replaced my code to get last fragment in backstack to this code(I am using this code in onBackPressed() to apply changes according to currentFragment assumed all fragments are added to backstack):
FragmentManager.BackStackEntry backStackEntryAt = getSupportFragmentManager().getBackStackEntryAt(getSupportFragmentManager().getBackStackEntryCount() - 1);
currentFragment = backStackEntryAt.getName();
You can use (make sure using 25.2.0 or higher )
supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentAttached(fm: FragmentManager?, f: Fragment?, context: Context?) {
f?.let { fList.add(it) }
}
override fun onFragmentDetached(fm: FragmentManager?, f: Fragment?) {
f?.let { fList.remove(it) }
}
}, false)
Instead of using getFragments()

Cannot use FakeHttpLayer of Robolectric (NullPointerException when calling getFakeHttpLayer)

Update 1
After removing the ServiceTestCase extend of my test class, I edited my gradle file to change the testInstrumentationRunner to org.robolectric.RobolectricTestRunner but I get another error :
Running tests
Test running started
Test running failed: Instrumentation run failed due to 'java.lang.NoSuchMethodException'
Empty test suite.
I searched Google but I could not find out why I get this error message. Here is the whole gradle file :
apply plugin: 'com.android.application'
android {
compileSdkVersion 19
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "foo.bar.testappsdk"
minSdkVersion 9
targetSdkVersion 19
testApplicationId "novom.anyware.anywaresdk.test"
testInstrumentationRunner "org.robolectric.RobolectricTestRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
exclude 'LICENSE.txt'
}
sourceSets {
instrumentTest.setRoot('src/androidTest')
}
}
dependencies {
compile 'com.android.support:support-v4:19.1.0'
compile 'com.android.support:appcompat-v7:19.1.0'
compile 'com.google.android.gms:play-services:6.5.87'
compile 'novom.anyware.anywaresdk:anywaresdk#aar'
androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.2.1'
androidTestCompile 'org.robolectric:robolectric:2.4'
androidTestCompile 'junit:junit:4.12'
}
End of update 1
I am trying to use Robolectric 2.4 to test the network calls of my Android Library. The problem is that I can't even get access to the FakeHttpLayer of Robolectric without getting a NullPointerException.
java.lang.NullPointerException: Attempt to invoke virtual method 'org.robolectric.tester.org.apache.http.FakeHttpLayer org.robolectric.shadows.ShadowApplication.getFakeHttpLayer()' on a null object reference
at org.robolectric.Robolectric.getFakeHttpLayer(Robolectric.java:1239)
at novom.anyware.anywaresdk.test.AWRSyncServiceTest.test_3_get_config(AWRSyncServiceTest.java:61)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837)
There is my Test class :
#RunWith(RobolectricTestRunner.class)
public class AWRSyncServiceTest extends ServiceTestCase<AWRSyncService> {
private static final String TAG = "AWRSyncServiceTest";
private AWRSyncService syncService;
public AWRSyncServiceTest() {
super(AWRSyncService.class);
}
#Override
protected void setUp() throws Exception {
Log.d(TAG, "setUp");
super.setUp();
IBinder service = bindService(new Intent(getContext(), AWRSyncService.class));
AWRSyncService.SyncServiceBinder binder = (AWRSyncService.SyncServiceBinder) service;
syncService = binder.getService();
}
#Override
protected void tearDown() throws Exception {
Log.d(TAG, "tearDown");
super.tearDown();
}
public void test_1_preconditions() {
Log.d(TAG, "test_1_preconditions");
assertNotNull(syncService);
assertNotNull(syncService.getApplicationContext());
}
public void test_3_get_config() {
Robolectric.getFakeHttpLayer();
}
}
Am I missing some basic configuration that must be set to Robolectric before being able to use it? I can't find any good tutorial that would help me to understand what I did wrong.
Thank you
Not sure if this is why you have this specific problem, but one issue is that you are extending a ServiceTestCase. This is a problem, because you are now mixing Robolectric with Android Unit Tests.
Robolectric tests run on the JVM, not on device. Android Unit Tests ran on device.
You might also want to check this out in terms of how to test your service: http://robolectric.org/starting-components/
Probably it's because you are extending it from ServiceTestCase class. Don't use Android Unit Test suite for that. Also be sure you have created that class on JUnit 4.
Another thing is you should build the service with Robolectric way. Like this;
Robolectric.buildService(AWRSyncService.class).bind()
EDIT : Add these fields to your build.gradle file, these are from robolectric gradle plugin
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.robolectric:robolectric-gradle-plugin:0.13.2'
}
}
apply plugin: 'robolectric'
android {
sourceSets {
androidTest {
setRoot('src/androidTest')
}
}
robolectric {
include '**/*Test.class'
}

support v7 action bar with ActionBarActivity

There is no problem with importing, but problems come with activity. When I change extends fromActivity to ActionBarActivity I get a lot of problems...
Why with extends ActionBarActivity I have no more methods like findViewById() or getFragmentManager(), etc.. How can I fix it?
Add the following lines into your build.gradle.
dependencies {
// other dependencies
compile "com.android.support:appcompat-v7:18.0.+"
}
Your build.gradle file should look similar to below:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.1.1"
defaultConfig {
minSdkVersion 7
targetSdkVersion 19
}
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
}

Categories