How to install Android apk from code in unity

You can build a jar/aar plugin and call it from C#. That's more easier to do.

Another solution is to use AndroidJavaObject and AndroidJavaClass to do this directly without a plugin. Doing it with AndroidJavaObject and AndroidJavaClass requires lots of testing to get it right. Below is what I use to do that. It downloads an APK then installs it.

First of all create a UI text called "TextDebug" so it you will see what's going on during the download/install. If you don't do this you must comment out or remove all the GameObject.Find("TextDebug").GetComponent<Text>().text... line of code.

void Start()
{
    StartCoroutine(downLoadFromServer());
}

IEnumerator downLoadFromServer()
{
    string url = "http://apkdl.androidapp.baidu.com/public/uploads/store_2/f/f/a/ffaca37aaaa481003d74725273c98122.apk?xcode=854e44a4b7e568a02e713d7b0af430a9136d9c32afca4339&filename=unity-remote-4.apk";


    string savePath = Path.Combine(Application.persistentDataPath, "data");
    savePath = Path.Combine(savePath, "AntiOvr.apk");

    Dictionary<string, string> header = new Dictionary<string, string>();
    string userAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36";
    header.Add("User-Agent", userAgent);
    WWW www = new WWW(url, null, header);


    while (!www.isDone)
    {
        //Must yield below/wait for a frame
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Stat: " + www.progress;
        yield return null;
    }

    byte[] yourBytes = www.bytes;

    GameObject.Find("TextDebug").GetComponent<Text>().text = "Done downloading. Size: " + yourBytes.Length;


    //Create Directory if it does not exist
    if (!Directory.Exists(Path.GetDirectoryName(savePath)))
    {
        Directory.CreateDirectory(Path.GetDirectoryName(savePath));
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Created Dir";
    }

    try
    {
        //Now Save it
        System.IO.File.WriteAllBytes(savePath, yourBytes);
        Debug.Log("Saved Data to: " + savePath.Replace("/", "\\"));
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Saved Data";
    }
    catch (Exception e)
    {
        Debug.LogWarning("Failed To Save Data to: " + savePath.Replace("/", "\\"));
        Debug.LogWarning("Error: " + e.Message);
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error Saving Data";
    }

    //Install APK
    installApp(savePath);
}

public bool installApp(string apkPath)
{
    try
    {
        AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
        string ACTION_VIEW = intentObj.GetStatic<string>("ACTION_VIEW");
        int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic<int>("FLAG_ACTIVITY_NEW_TASK");
        AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);

        AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
        AndroidJavaClass uriObj = new AndroidJavaClass("android.net.Uri");
        AndroidJavaObject uri = uriObj.CallStatic<AndroidJavaObject>("fromFile", fileObj);

        intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
        intent.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_TASK);
        intent.Call<AndroidJavaObject>("setClassName", "com.android.packageinstaller", "com.android.packageinstaller.PackageInstallerActivity");

        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        currentActivity.Call("startActivity", intent);

        GameObject.Find("TextDebug").GetComponent<Text>().text = "Success";
        return true;
    }
    catch (System.Exception e)
    {
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error: " + e.Message;
        return false;
    }
}

For Android API 24 and above, this requires a different code since the API changed. The C# code below is based on the this Java answer.

//For API 24 and above
private bool installApp(string apkPath)
{
    bool success = true;
    GameObject.Find("TextDebug").GetComponent<Text>().text = "Installing App";

    try
    {
        //Get Activity then Context
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject unityContext = currentActivity.Call<AndroidJavaObject>("getApplicationContext");

        //Get the package Name
        string packageName = unityContext.Call<string>("getPackageName");
        string authority = packageName + ".fileprovider";

        AndroidJavaClass intentObj = new AndroidJavaClass("android.content.Intent");
        string ACTION_VIEW = intentObj.GetStatic<string>("ACTION_VIEW");
        AndroidJavaObject intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);


        int FLAG_ACTIVITY_NEW_TASK = intentObj.GetStatic<int>("FLAG_ACTIVITY_NEW_TASK");
        int FLAG_GRANT_READ_URI_PERMISSION = intentObj.GetStatic<int>("FLAG_GRANT_READ_URI_PERMISSION");

        //File fileObj = new File(String pathname);
        AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
        //FileProvider object that will be used to call it static function
        AndroidJavaClass fileProvider = new AndroidJavaClass("android.support.v4.content.FileProvider");
        //getUriForFile(Context context, String authority, File file)
        AndroidJavaObject uri = fileProvider.CallStatic<AndroidJavaObject>("getUriForFile", unityContext, authority, fileObj);

        intent.Call<AndroidJavaObject>("setDataAndType", uri, "application/vnd.android.package-archive");
        intent.Call<AndroidJavaObject>("addFlags", FLAG_ACTIVITY_NEW_TASK);
        intent.Call<AndroidJavaObject>("addFlags", FLAG_GRANT_READ_URI_PERMISSION);
        currentActivity.Call("startActivity", intent);

        GameObject.Find("TextDebug").GetComponent<Text>().text = "Success";
    }
    catch (System.Exception e)
    {
        GameObject.Find("TextDebug").GetComponent<Text>().text = "Error: " + e.Message;
        success = false;
    }

    return success;
}

EDIT:

If you get the Exception:

Attempt to invoke virtual method 'android.content.res.XmlResourceParser android.content.pm.packageItemInfo.loadXmlMetaData(android.c‌​ontent.pm.PackageMan‌​ager.java.lang.Strin‌​g)'

You have to do few things.

1.Copy "android-support-v4.jar" from your "AndroidSDK/extras/android/support/v4/android-support-v4.jar" directory to your "UnityProject/Assets/Plugins/Android" directory.

2.Create a file called "AndroidManifest.xml" in your UnityProject/Assets/Plugins/Android directory and put the code below into it.

Make sure to replace "com.company.product" with your own package name. There are 2 instances where this appeared. You must replace both of them:

These are found in package="com.company.product" and android:authorities="com.company.product.fileprovider". Don't change or remove the "fileprovider" and don't change anything else.

Here is the "AndroidManifest.xml" file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal" android:versionName="1.0" android:versionCode="1">
  <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
  <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true">
    <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
      <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
    </activity>

    <provider
          android:name="android.support.v4.content.FileProvider"
          android:authorities="com.company.product.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true">
      <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths"/>
    </provider>

  </application>
  <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
</manifest>

3.Create a new file called "provider_paths.xml" in your "UnityProject/Assets/Plugins/Android/res/xml" directory and put the code below in it. As you can see, you have to create a res and then an xml folder.

Make sure to replace "com.company.product" with your own package name. It only appeared once.

Here is what you should put into this "provider_paths.xml" file:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
  <!--<external-path name="external_files" path="."/>-->
  <external-path path="Android/data/com.company.product" name="files_root" />
  <external-path path="." name="external_storage_root" />
</paths>

I just wanted to add an update to the fantastic answer given by @Programmer, to reflect changes to the Android SDK and Unity. I hope it can be useful to someone else. I am working with SDK version 26 and Unity 2017.3.1. I am new to almost all of this so please do correct me if I've missed or misunderstood anything!

  1. The android-support-v4.jar (used to get the FileProvider class) is no longer available. For versions up to 24.1.1 it is located at Android\sdk\extras\android\m2repository\com\android\support\support-v4\24.1.1 but for versions after that you must instead use support-core-utils at Android\sdk\extras\android\m2repository\com\android\support\support-core-utils. Instead of a jar file use the relevant .aar file and drag that into a Plugins folder in your Unity project.
  2. You need to add android.permission.REQUEST_INSTALL_PACKAGES to your AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.productsomethingelse" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal" android:versionName="1.0" android:versionCode="1">
      <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
      <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true">
        <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name">
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
          <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    
        <provider
              android:name="android.support.v4.content.FileProvider"
              android:authorities="com.company.product.fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
          <meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/provider_paths"/>
        </provider>
    
      </application>
      <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
      <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" />
    </manifest>
    

    Note that I've also changed the first instance of com.company.product to com.company.productsomethingelse

  3. That should now build ok and work, although during the build process Unity is giving the warning OBSOLETE - Providing Android resources in Assets/Plugins/Android/res is deprecated, please move your resources to an AAR or an Android Library.. To get round this create a new zip file and put your AndroidManifest.xml at the top level of the zip. Then add the provider_paths.xml detailed by @Programmer into the zip in the folder structure res/xml/provider_paths.xml. Rename the zip to give it a .aar file extension and then drag it into your Unity project Assets/Plugins folder. The reason I changed the AndroidManifest.xml entry to com.company.productsomethingelse is that when I used com.company.product the Unity build process was throwing up a naming conflict. I think because the manifest is now in a separate aar it needs to have a distinct package name.


With later versions of Unity, it gets a bit more complicated. Assets/Plugins/Android/res got deprecated. And with Android 9.0 android.support.v4 got merged into androidx.core and everything got renamed and moved around. Fortunately Unity is a bit better about supporting Android plugins now, so with this solution you no longer have to add any jar or aar to your project.

Note that Android has a bunch of nag screens associated with this install process. There's a one-time accept screen for untrusted builds per app, and if you have google play on the device, play protect adds a bunch of screens that make your app look like malware. (Which is a good thing, as you should only be doing this stuff on kiosk-mode style devices you own, where you can turn off Play Protect.)

Adding to Programmer's answer. In Unity 2019 and 2020, you can compile a plugin directly in Unity, and you no longer need the jar file. In 2019, it needs to be in Assets/Plugins/Android and have a couple extra files. In 2020, the folder just needs the suffix .androidlib and can be located anywhere in Assets/.

package.androidlib
  src
    main
      res
        xml
          provider_paths.xml
      AndroidManifest.xml
  build.gradle
  AndroidManifest.xml  (only for 2019)
  project.properties  (only for 2019)

provider_paths.xml: As explained by Programmer.

AndroidManifest.xml: is mainly there to give this new library a bundle ID. This should not match any other IDs; it can be anything and usually it's com.companyname.packagename. Note that it's within the main/ folder

We can also do the rest of the AndroidManifest.xml stuff here, because all AndroidManifest.xml files will get merged in the final APK nowadays. The FileProvider package has changed to androidx.core.content.FileProvider.

I've noticed you need android.permission.REQUEST_INSTALL_PACKAGES; but I'm not sure whether you need READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE like Kaushix suggests. (Maybe on certain devices? I think this is covered by Project Settings->Write Permission.)

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.anything.anythingelse">
    <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/provider_paths"/>
        </provider>
    </application>
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
</manifest>

build.gradle: This should probably match your project target and min SDK version. It's OK if it's less, but target needs to be at least 28 to use androidx.

apply plugin: 'com.android.library'

android {
    compileSdkVersion 28


    defaultConfig {
        minSdkVersion 16
        targetSdkVersion 28
    }
}

dependencies {
    implementation 'androidx.appcompat:appcompat:1.1.0'
}

For 2019, the extra AndroidManifest.xml and project.properties files purely exist to tell Unity to build this folder. In 2020, Unity's smart enough to not need them.

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- This extra manifest, as well as project.properties in this folder shouldn't be necessary with the newer gradle project format. Can remove if you upgrade to 2020.1. -->
</manifest>

project.properties:

android.library=true

AndroidPostProcess.cs:

We also need an editor script to enable AndroidX support in the main gradle file, and turn on Jetifier, which should fix any other plugins compiled against the old android.support libraries.

using UnityEditor.Android;

public class AndroidPostProcess : IPostGenerateGradleAndroidProject
{
    public int callbackOrder => 0;
    public void OnPostGenerateGradleAndroidProject(string path)
    {
        string gradlePropertiesPath = path + "/gradle.properties";
        string[] lines = File.ReadAllLines(gradlePropertiesPath);

        StringBuilder builder = new StringBuilder();
        foreach (string line in lines)
        {
            if (line.Contains("android.useAndroidX"))
            {
                continue;
            }
            if (line.Contains("android.enableJetifier"))
            {
                continue;
            }
            builder.AppendLine(line);
        }
        builder.AppendLine("android.useAndroidX=true");
        builder.AppendLine("android.enableJetifier=true");
        File.WriteAllText(gradlePropertiesPath, builder.ToString());
    }
}

Here we have to change your manifest file. We have to give Read & Write permissions. after change this we can easily install downloaded application file.

Without these permissions we can't access Android External Files.

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.company.product" xmlns:tools="http://schemas.android.com/tools" android:installLocation="preferExternal" android:versionName="1.0" android:versionCode="1">
      <supports-screens android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true" android:anyDensity="true" />
      <application android:theme="@style/UnityThemeSelector" android:icon="@drawable/app_icon" android:label="@string/app_name" android:debuggable="true">
        <activity android:name="com.unity3d.player.UnityPlayerActivity" android:label="@string/app_name">
          <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
          <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>

        <provider
              android:name="android.support.v4.content.FileProvider"
              android:authorities="com.company.product.fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
          <meta-data
              android:name="android.support.FILE_PROVIDER_PATHS"
              android:resource="@xml/provider_paths"/>
        </provider>

      </application>
      <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-sdk android:minSdkVersion="16"   android:maxSdkVersion="29"  />
    </manifest>

Comments

  1. Roman

    • 2015/8/3

    4 Answers · 1.Copy "android-support-v4.jar" from your "AndroidSDK/extras/android/support/v4/android-support-v4. · 2.Create a file called "AndroidManifest.xml" in 

  2. Maxwell

    • 2015/9/13

    1 .Copy "android-support-v4.jar" from your "AndroidSDK/extras/android/support/v4/android-support-v4.jar" directory to your "UnityProject/Assets/Plugins/Android" directory. 2 .Create a file called "AndroidManifest.xml" in your UnityProject/Assets/Plugins/Android directory and put the code below into it.

  3. Lombardi

    • 2016/6/26

    You cannot install an apk in Unity. But i guess what you meant here was "if there is any way to update your android app via code, 

  4. Rodney

    • 2018/12/23

    But what I want is to install the app within my unity app. So lets say I have there will be one button of install in my app & by clicking on it .apk is which is stored in my device will be installed in my phone. It is kind of what the play store does for installing the app. Can you please guide me for the same? Thanks in Advance.

  5. Gunner

    • 2021/6/19

    Selecting Internal hides the Export Project checkbox. Gradle - Generate the output package (APK) using the Gradle build system. Supports direct Build and Run 

  6. Nathanael

    • 2019/10/25

    1.Copy "android-support-v4.jar" from your "AndroidSDK/extras/android/support/v4/android-support-v4.jar" directory to your "UnityProject/Assets/Plugins/Android" directory. 2 .Create a file called "AndroidManifest.xml" in your UnityProject/Assets/Plugins/Android directory and put the code below into it.

  7. Orion

    • 2018/3/2

    You also need to install the Android Software Development Kit (SDK) and the Native Development Kit (NDK) to build and run any code on your Android device.

  8. Miguel

    • 2017/8/3

    Internal (deprecated) - Generate the output package (APK) using the internal Unity build process, based on Android SDK utilities. Selecting Internal hides the Export Project checkbox. Gradle - Generate the output package (APK) using the Gradle build system. Supports direct Build and Run and exporting the Project to a directory.

  9. Theo

    • 2018/6/16

    Unity is a cross-platform game engine used by many games on the Google During the installation of the Unity Editor, make sure to include 

  10. Miller

    • 2018/5/29

    How to Build Unity Project to Android (apk)This tutorial is simple way to export unity project to apkTools:Unity Download - https://unity3d.com/get-unity/dow

  11. Miles

    • 2019/11/25

    I found snippet for Java. How can I write such a code in C# Unity? Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.

  12. Carbone

    • 2015/10/16

    Go to Settings > Developer options (or, if this does not work, on some devices the path is Settings > System > Developer options ), and check the USB debugging checkbox. Android now enters debug mode when it is connected to a computer via USB. Connect your device to your computer using a USB cable.

  13. Ramirez

    • 2016/10/5

    Export an .apk file. If you don't need an Android Studio project, building directly from Unity is the fastest way to run your app on an Android device.

  14. Thanasi

    • 2015/5/9

    To import the plugin, follow these steps: Download the latest release from Google Play Plugins for Unity releases. Import the .unitypackage file by selecting the Unity IDE menu option Assets > Import package > Custom Package and importing all items.

  15. Alvin

    • 2017/1/31

    In the Unity Build Settings window, click Build and Run. Unity builds your project into an Android APK, installs it on your device, and launches it.

  16. Tomas

    • 2019/3/3

    Unity beginners who have only developed Android clients before need Release an APK package and change the package name and version code.

Comments are closed.

Recent Posts