c# android unity3d android-intent

c# - Cómo instalar apk Android desde el código en la unidad



unity3d android-intent (2)

Puede crear un complemento jar / aar y llamarlo desde C #. Eso es más fácil de hacer.

Otra solución es usar AndroidJavaObject y AndroidJavaClass para hacer esto directamente sin un complemento. Hacerlo con AndroidJavaObject y AndroidJavaClass requiere muchas pruebas para hacerlo bien. A continuación se muestra lo que uso para hacer eso. Descarga un APK y luego lo instala.

En primer lugar, cree un texto de interfaz de usuario llamado "TextDebug" para que vea lo que sucede durante la descarga / instalación. Si no lo hace, debe comentar o eliminar toda la línea de código GameObject.Find("TextDebug").GetComponent<Text>().text...

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; } }

Para Android API 24 y superior, esto requiere un código diferente ya que la API cambió. El código C # a continuación se basa en la respuesta de Java.

//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; }

EDITAR:

Si obtienes la excepción:

Intente invocar el método virtual ''android.content.res.XmlResourceParser android.content.pm.packageItemInfo.loadXmlMetaData (android.c‌ ontent.pm.PackageMan‌ ager.java.lang.Strin‌ g)''

Tienes que hacer pocas cosas.

1. Copie "android-support-v4.jar" desde su directorio "AndroidSDK / extras / android / support / v4 / android-support-v4.jar" a su directorio "UnityProject / Assets / Plugins / Android" .

2.Cree un archivo llamado "AndroidManifest.xml" en su directorio UnityProject / Assets / Plugins / Android y coloque el código a continuación.

Asegúrese de reemplazar "com.company.product" con su propio nombre de paquete . Hay 2 instancias donde esto apareció. Debes reemplazar ambos:

Estos se encuentran en package = "com.company.product" y android: autoridades = "com.company.product.fileprovider" . No cambie ni elimine el "proveedor de archivos" y no cambie nada más.

Aquí está el archivo "AndroidManifest.xml":

<?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. Cree un nuevo archivo llamado " provider_paths.xml " en su directorio "UnityProject / Assets / Plugins / Android / res / xml" y coloque el código a continuación. Como puede ver, debe crear una resolución y luego una carpeta xml .

Asegúrese de reemplazar "com.company.product" con su propio nombre de paquete . Solo apareció una vez .

Esto es lo que debe poner en este archivo " provider_paths.xml ":

<?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>

Encontré un fragmento para Java. ¿Cómo puedo escribir dicho código en C # Unity?

Intent intent = new Intent(Intent.ACTION_VIEW); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setDataAndType(Uri.fromFile(new File("link to downloaded file")),"application/vnd.android.package-archive"); startActivity(intent);


Solo quería agregar una actualización a la fantástica respuesta dada por @Programmer, para reflejar los cambios en Android SDK y Unity. Espero que pueda ser útil para alguien más. Estoy trabajando con SDK versión 26 y Unity 2017.3.1. Soy nuevo en casi todo esto, ¡así que corríjame si me he perdido o no he entendido algo!

  1. Android-support-v4.jar (usado para obtener la clase FileProvider) ya no está disponible. Para las versiones hasta 24.1.1, se encuentra en Android / sdk / extras / android / m2repository / com / android / support / support-v4 / 24.1.1 pero para las versiones posteriores, debe usar support-core-utils en Android / sdk / extras / android / m2repository / com / android / support / support-core-utils . En lugar de un archivo jar, use el archivo .aar relevante y arrástrelo a la carpeta Plugins en su proyecto de Unity.
  2. Debe agregar android.permission.REQUEST_INSTALL_PACKAGES a su 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>

    Tenga en cuenta que también he cambiado la primera instancia de com.company.product a com.company.productsomethingelse

  3. Eso ahora debería compilarse bien y funcionar, aunque durante el proceso de compilación, Unity está dando la advertencia OBSOLETO: proporcionar recursos de Android en Assets / Plugins / Android / res está en desuso, mueva sus recursos a un AAR o una Biblioteca de Android. . Para evitar esto, cree un nuevo archivo zip y coloque su AndroidManifest.xml en el nivel superior del zip. Luego agregue el provider_paths.xml detallado por @Programmer en el zip en la estructura de carpetas res / xml / provider_paths.xml . Cambie el nombre del zip para darle una extensión de archivo .aar y luego arrástrelo a la carpeta Assets / Plugins del proyecto Unity. La razón por la que cambié la entrada AndroidManifest.xml a com.company.productsomethingelse es que cuando utilicé com.company.product, el proceso de compilación de Unity generaba un conflicto de nombres. Creo que debido a que el manifiesto ahora está en un aar separado, debe tener un nombre de paquete distinto.