skip to Main Content

This is my first time asking a question on stack overflow, let me know if I missed mandatory informations.
I’ll try to summarize efficiently.

The goal

I’m coding a Unity Android App, in which I want to implement an auto-update functionnality.
After Unity has downloaded the updated version of my app from a server, I want it to open it programmaticaly.

On Unity side, everything works fine (I can call custom made java functions from my *.aar file).
On Android Studio side (which I’m using for the first time), I’m implementing a "OpenApk()" method.

My code

Here is what I import to use Android tools:

import androidx.core.content.FileProvider;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import java.io.File;

Here is my function in Android Studio:

public void openApkFile(String _filePath) {
    try {
        File apkFullPath = new File(context.getFilesDir() + File.separator + _filePath);
        Uri apkUri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", apkFullPath);
        Intent intent = new Intent(Intent.ACTION_VIEW);

        intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        context.startActivity(intent);
    }
    catch (Exception e) {
        printToastMessage(e.toString(), true);
    }
}

Here is my AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.opu.intranet"> <!-- I ADDED MY PACKAGE NAME HERE -->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    <!-- ADDING THIS PROVIDER VIA XML PREVENTS APP FROM RUNNING (CRASH ON EXECUTION) -->
    <application>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>

Also I added:

android.useAndroidX=true # WAS ALREADY PRESENT BY DEFAULT
android.enableJetifier=true

to gradle.properties.

Le problem

Whenever I build my *.aar package and add it to Unity, if the AndroidManifest.xml file contains , the app won’t run anymore on my phone.
It closes immediately after opening, and the OS asks me to wait for the developer to solve the problem haha.

[EDIT]: Thanks to "Retire Ninja"’s comment, I discovered "logcat"…
Here is the error log:

FATAL EXCEPTION: main
Process: com.opu.securityconcilapp, PID: 29513
java.lang.RuntimeException: Unable to get provider androidx.core.content.FileProvider: java.lang.ClassNotFoundException: Didn’t find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/base.apk"],nativeLibraryDirectories=[/data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/lib/arm64, /data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] at android.app.ActivityThread.installProvider(ActivityThread.java:8463)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:7963)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7649)
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2478)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Caused by: java.lang.ClassNotFoundException: Didn’t find class "androidx.core.content.FileProvider" on path: DexPathList[[zip file "/data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/base.apk"],nativeLibraryDirectories=[/data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/lib/arm64, /data/app/~~jLNBDfF2HmsctyymOxViwQ==/com.opu.securityconcilapp-bZsahkZ0i3R7T1ZoK0sdTw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/system_ext/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at android.app.AppComponentFactory.instantiateProvider(AppComponentFactory.java:147)
at android.app.ActivityThread.installProvider(ActivityThread.java:8447)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:7963) 
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7649) 
at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2478) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loopOnce(Looper.java:230) 
at android.os.Looper.loop(Looper.java:319) 
at android.app.ActivityThread.main(ActivityThread.java:8893) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) 

Software versions

Unity: 2022.3.20f1
Android Studio: 2023.2.1
Gradle: 7.1.2 on Unity side, 8.4 on Android Studio side
Android: 14 (API 34)

Target SDK : API 24 or higher

Fix attempts

I spent 2 days reading similar discussions about this everywhere, and testing multiple combinations. I even unzipped AndroidFileOpener (See here) by Mihail5412, a plugin I used before but stopped working after a while (Unity Editor package rename errors).

I tried removing "enableJetifier=true", using "android.support.v4.content.FileProvider" instead of "androidx.core.content.FileProvider" (with the required *.jar library added to the project but it created duplicates with androidx.core).

A huge thanks to anyone who will take the time to read me, please be sure I’ll follow that thread with attention.
Best regards.

2

Answers


  1. Chosen as BEST ANSWER

    I fixed the problem, a huge thanks to Bob Smith, Retired Ninja for their help here, and to Tomas1856 member of Unity Dev team on this thread.

    I have to add:

    -keep class androidx.core.content.FileProvider { *; }

    to proguard-user.txt, file to enable via Unity->Edit->Projects Settings->Player->Publishing Settings->Custom Proguard File. The file path is then showed by Unity below the toggle button.

    I also had to add:

    android.useAndroidX=true
    android.enableJetifier=true
    

    to gradleTemplate.properties, file to enable via Unity->Edit->Projects Settings->Player->Publishing Settings->Custom Gradle Properties Template.

    Final Android Studio AndroidManifest.xml configuration is:

    <application>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.provider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
    

    I still have issues with file path configuration to allow the plugin to open the APK (Failed to find configured root that contains [...]), but I'll ask a new question for that, since it is off topic.


  2. Try this solution:

    1. Add

    src/main/res/xml/file_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <external-files-path name="images" path="Pictures" />
    </paths>
    
    1. Add

    src/main/AndroidManifest.xml

    <provider
        android:name="com.image.crop.lib.DocumentScannerFileProvider"
        android:authorities="com.image.crop.provider"
        android:exported="false"
        android:grantUriPermissions="true">
      <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/file_paths" />
    </provider>
    
    1. Add

    src/main/java/com/image/crop/lib/DocumentScannerFileProvider.kt

    package com.image.crop.lib
    
    import androidx.core.content.FileProvider
    
    class DocumentScannerFileProvider : FileProvider() {}
    
    
    1. How to use
    Intent intent = new Intent(Intent.ACTION_VIEW);
    File apkFullPath = new File(context.getFilesDir() + File.separator + _filePath);
    apkFullPath = photoFile.absolutePath
    val apkUri: Uri = FileProvider.getUriForFile(
        activity, "com.image.crop.provider", apkFullPath
    )
    intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
    intent.putExtra(MediaStore.EXTRA_OUTPUT, apkUri)
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    
    context.startActivity(intent);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search