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.content.pm.PackageManager.java.lang.String)'
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 make a apk AutoInstall using Unity
In the link you mentioned in your question, the author said:
For Android API 24 and above, this requires a different code since
the API changed.
So you have to check the version of your device using methods like this and then call the appropriate function.
How to Build Apk from Unity with custom android Code
First solution is generate .jar from your java code and put it in Assets/Plugins/Android/
folder as mentioned in comments
Another solution is to use custom gradle template, follow this link to enable custom gradle template. Then, in your Assets/Plugins/Android/mainTemplate.gradle
file under android folder add this:
sourceSets
{
main
{
java
{
srcDirs = ['src']
// 'D:/Projects/somep/app/src/main/java/com'
srcDirs += ['"PathToYourJavaCode"']
}
}
}
So your gradle file should look like this
Unable to install APK to device
I got the Solution.
Create New Folder in any other drive, and copy the folder one by one from older sdk to new sdk folder, and take build each time you paste the folder.
In my case there is an extra folder is corrupted and found like this , and i removed that folder and it works fine now.
running a game apk from another application
How can I create a new app that shows some info to the user, and the runs the game?
Either the APK is installed, or it is not.
If the APK is installed, use startActivity()
to start up one of its activities.
If the APK is not installed, you cannot "run" it. You can use an ACTION_VIEW
Intent
with startActivity()
to ask the user to install it. Be sure to specify the right MIME type on the Intent
(application/vnd.android.package-archive
).
I could not find a description of a way to do it without installing both .apk independently.
That is because APK files cannot be "run". They can be installed.
Related Topics
Get Transactionscope to Work with Async/Await
Sometimes Adding a Wcf Service Reference Generates an Empty Reference.Cs
Automatically Inotifypropertychanged
Automapper: Update Property Values Without Creating a New Object
Replace Only Some Groups with Regex
Redirecting Unauthorized Controller in ASP.NET MVC
.Net Code to Send Zpl to Zebra Printers
Custom Method Names in ASP.NET Web API
What Does the M Stand for in C# Decimal Literal Notation
Is There an Alternative to String.Replace That Is Case-Insensitive
Can't Connect to Localhost on SQL Server Express 2012/2016
How to Stream Webcam Video with C#
Is There a C# Case Insensitive Equals Operator
Log4Net Rolling Daily Filename with Date in the File Name
Anonymous Method in Invoke Call
Validation: How to Inject a Model State Wrapper with Ninject