1

I'm pretty new to android development and I am trying to dynamically load a dex file after downloading it from firebase storage (so it can be changed on the fly without updating the app itself). I am trying to follow this Medium Article.

But the DexClassloader always gives this error which seems to just be a symptom on incorrect downloading (File size is 0MB after download):

E/System: java.io.IOException: No original dex files found for dex location /data/user/0/com.example.calculator/cache/Calc1387497247.dex
        at dalvik.system.DexFile.openDexFileNative(Native Method)
        at dalvik.system.DexFile.openDexFile(DexFile.java:367)
        at dalvik.system.DexFile.<init>(DexFile.java:148)
        at dalvik.system.DexFile.loadDex(DexFile.java:219)
        at dalvik.system.DexPathList.loadDexFile(DexPathList.java:362)
        at dalvik.system.DexPathList.makeElements(DexPathList.java:313)
        at dalvik.system.DexPathList.makeDexElements(DexPathList.java:263)
        at dalvik.system.DexPathList.<init>(DexPathList.java:126)
        at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:48)
        at dalvik.system.DexClassLoader.<init>(DexClassLoader.java:57)
        at com.example.calculator.MainActivity.onCreate(MainActivity.java:64)
        at android.app.Activity.performCreate(Activity.java:6679)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2618)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
        at android.app.ActivityThread.-wrap12(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:154)
        at android.app.ActivityThread.main(ActivityThread.java:6119)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

I am getting the dex from the linked github project on the medium article. Just building the project and then unzipping and using the dex file (I've tried using the whole apk but it fails the same) It looks like it is downloading fine and I am able to find the temp file when checking.

I've tried the suggestions in a couple stackoverflow questions. ex1 ex2 But nothing worked.

I was able to test the files size after downloading it and it shows the tempfile is 0 MB. So, it must be downloading incorrectly and the error is a symptom of that.

I figure I'm not the only one that has tried to follow this article. So, if anyone has has a fix or can point me in the direction of a working github example project that would be much appreciated.

Source code: MainActivity.java

package com.example.calculator;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.FirebaseApp;
import com.google.firebase.storage.FileDownloadTask;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;

import dalvik.system.DexClassLoader;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FirebaseApp.initializeApp(this);

        FirebaseStorage storage = FirebaseStorage.getInstance();

        // Create a storage reference from our app
        StorageReference storageRef = storage.getReference();


        StorageReference gsReference = storage.getReferenceFromUrl("gs://dcl-demo.appspot.com/Calc.dex");



        Log.e("Cache Dir: ", getCacheDir().getAbsolutePath());

        try {
            File outputDir = getCacheDir().getAbsoluteFile(); // context being the Activity pointer
            File localFile = File.createTempFile("Calc", ".dex", outputDir);

            gsReference.getFile(localFile);

            Log.e("Local File Path: ", localFile.getAbsolutePath());
            Log.e("Local File Name: ", localFile.getName());

            File file = new File(localFile.getAbsolutePath());
            if(file.exists()) {
                Log.e("THE FILE EXISTS: ", "EXISTS");
            }

            final DexClassLoader classLoader = new DexClassLoader(localFile.getAbsolutePath(), getCacheDir().getAbsolutePath(), null, this.getClass().getClassLoader());

            try {
               Class<?> myOwnClass = classLoader.loadClass("com.example.calculator.DynamicCalculator");
                Method addMethod = myOwnClass.getMethod("add", Double.class, Double.class);
                double result = (double) addMethod.invoke(null, 5.0, 3.0);

                Log.e("Returned Result: ", String.valueOf(result));

            } catch (Exception e) {
               e.printStackTrace();
            }


            } catch (Exception e) {
                e.printStackTrace();
            }

    }}

BuildGradle (app):

    apply plugin: 'com.android.application'
    apply plugin: 'com.google.gms.google-services'
    
    android {
        compileSdkVersion 29
        buildToolsVersion "30.0.0"
    
        defaultConfig {
            applicationId "com.example.calculator"
            minSdkVersion 23
            targetSdkVersion 29
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            debug {
                minifyEnabled false
            }
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'androidx.appcompat:appcompat:1.2.0'
        implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
        //implementation 'com.google.firebase:firebase-analytics:17.5.0'
        implementation 'com.google.firebase:firebase-storage:19.2.0'
        testImplementation 'junit:junit:4.12'
        androidTestImplementation 'androidx.test.ext:junit:1.1.2'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    }

BuildGradle (project):

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

buildscript {
    
    repositories {
        google()
        jcenter()
        
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.1'
        classpath 'com.google.gms:google-services:4.3.3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.calculator">

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

0 Answers0