Installing APK from within Unity (Using Intent?)

I want to ship an apk to a remote client.

In the past, I used a process that let the user download the file in the browser from within Unity:


Which works, but then the client has to manually install the downloaded APK afterwards (4 specific clicks needed)

I am looking to automate this process.
Is there any Intent that i can use / other solutions to launch the MagicLeap2 application installer directly?

E.g. I saw that there are a couple of Intents exposed Intents | MagicLeap Developer Documentation
But on the Unity side I have not had success (e.g. I tried approaches similar to c# - How to install Android apk from code in unity - Stack Overflow

Any help appreciated.

When you refer to 4 clicks, are these the clicks that appears directly from the system? Currently, we do not provide an alternative method of installing applications. That said, I can provide your feedback to our voice of customer team.

Hey @footballdaniel , would you be able to elaborate on the failures you mentioned when trying to do the "android.permission.REQUEST_INSTALL_PACKAGES" flow?

thanks for coming back to me.

@kbabilinski, i currently have this (not optimal) user experience that my customer has to go through:

(1) Within the unity application, the user has to "confirm" to install a .apk file that is available through an sas-url that I host.
(2) I then use Application.OpenUrl to download the file to the clients device. This opens a browser window. The download progress is visible in the bottom left. After the download, the customer has to click on the file in the bottom left
(3) then the user gets prompted to install the apk
(4) and to open it if successful.

My goal: I would like the user to skip steps 2,3, and if possible 4.

Thanks for supporting this case, appreciate it.
To clarify, i would like to start the install process from within Unity, not through adb.

The attempt i made to install the package through intents looked like this:

AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject context = currentActivity.Call<AndroidJavaObject>("getApplicationContext");

// Create a Uri object for the APK file
AndroidJavaClass uriClass = new AndroidJavaClass("");
AndroidJavaObject fileObj = new AndroidJavaObject("", apkFilePath);
AndroidJavaObject uri = uriClass.CallStatic<AndroidJavaObject>("fromFile", fileObj);

// For Android N and above, use FileProvider to get URI
AndroidJavaClass fileProviderClass = new AndroidJavaClass("androidx.core.content.FileProvider"); // THIS ONE DOES NOT WORK. Probably have to pass in a JAR file!
string authority = currentActivity.Call<string>("getPackageName") + ".provider";
uri = fileProviderClass.CallStatic<AndroidJavaObject>("getUriForFile", context, authority, fileObj);

// Grant temporary read permission to the content URI
AndroidJavaClass intentClass = new AndroidJavaClass("android.content.Intent");
int flagGrantReadUriPermission = intentClass.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");
currentActivity.Call("grantUriPermission", currentActivity.Call<string>("getPackageName"), uri, flagGrantReadUriPermission);

// Create an intent to install the APK
AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", "android.intent.action.VIEW");
intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/");
intent.Call<AndroidJavaObject>("addFlags", 0x10000000); // FLAG_ACTIVITY_NEW_TASK
intent.Call<AndroidJavaObject>("addFlags", intent.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION"));

// Start the activity
currentActivity.Call("startActivity", intent);

I realized that in Android the FileProvider is no longer available and the script errors out on line:

AndroidJavaClass fileProviderClass = new AndroidJavaClass("androidx.core.content.FileProvider");

(Run on ML2, Unity2023.2.2f1, Development build with script debugging)

Until now i tried to open the file, but i have not used REQUEST_INSTALL_PACKAGES.

How would i approach that?

The issue you're encountering seems to be related to the androidx.core.content.FileProvider not being found at runtime. This could be because the AndroidX libraries are not included in your Unity project or the build. Since Unity internally uses its version of Android libraries, if specific AndroidX libraries are not included by default, you might need to ensure they are added manually or through dependency management or by compiling the script as an external plugin.

Thanks, yes, this is exactly what i am working on now. I will come back with a status update and post it here.

More generally: Its quite challenging to get a remote apk installation process to work with ML2.
Are there any best practices / suggestions from the developers at ML? I could not find any related documentation/forum when it comes to remote apk installation.

I know that the developers at ML2 used a similar approach inside of the SettingsIntentsLauncher.cs that is distributed with the Magic Leap Unity SDK:

public static void LaunchSystemSettings(string intentName)  
    using (var unityClass = new AndroidJavaClass(UnityPlayerClassName))  
    using (AndroidJavaObject currentActivityObject =  
    using (var intentObject = new AndroidJavaObject(  
                AndroidIntentClassName, intentName))  
    {        currentActivityObject.Call(AndroidIntentStartActivityFuncName, intentObject);  

It would be amazing if the SDK would have a function LaunchAppInstaller(Uri apk) that could be distributed with the SDK.

Is there any chance the code owner of this function could provide support / provide a suggestion? Thanks for checking.

Currently we do not provide this type of API as we rely on the AOSP APIs for app installation. However, I can provide this feedback to our voice of customer team.

Thanks for the information, I will try to write an android plugin that works for AOSP then and test it.

I will come back to you with how that goes. I am just looking for a way to update an apk remotely, and if ML2 does not provide an API for this (yet) I will try finding a solution myself.

Will come back to you, thanks for the support