Unity descarga recursos del servidor y llama a la interfaz de Android para implementar la instalación de Apk

I. Introducción

        Descargue el archivo Apk del servidor a través de la clase UnityWebRequest de Unity; encapsule e instale la interfaz del paquete de la aplicación en Android Studio, exporte el paquete AAR para que Unity lo llame, controle si la aplicación está instalada a través del receptor de transmisión y elimine el archivo Apk descargado. una vez completado, Unity El terminal llama a la interfaz encapsulada dentro de AAR a través de un script C#.

2. Paquete de funciones interactivas de Android

1. Creación de clases Java

(1) Crear una clase de llamada a método

        Esta clase se utiliza para crear un método para que Unity lo llame, el código específico es el siguiente:

import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;

import androidx.core.content.FileProvider;

import java.io.File;

public class InstallApkUtils {
    private Context mContext;
    private static InstallApkUtils mInstallApkUtils = null;
    private InitializeApkBroadcastReceiver apkBroadcastReceiver;
    public static String apkFilePath;

    public InstallApkUtils(Context context) {
        this.mContext = context;
    }

    public static InstallApkUtils getInstance(Context context){
        if (mInstallApkUtils == null) {
            mInstallApkUtils = new InstallApkUtils(context);
        }
        return mInstallApkUtils;
    }

    //安装Apk
    public void installApk(String filePath){
        apkFilePath = filePath;
        File apkFile = new File(filePath);
        if(!apkFile.exists()){
            return;
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);


        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){//安卓7.0以上
            Uri apkUri = FileProvider.getUriForFile(mContext,mContext.getPackageName() + ".fileProvider",apkFile);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri,"application/vnd.android.package-archive");
        }
        else {//安卓7.0以下
            intent.setDataAndType(Uri.parse("file://" + apkFile.toString()),"application/vnd.android.package-archive");
        }
        if(mContext.getPackageManager().queryIntentActivities(intent,0).size() > 0){
            mContext.startActivity(intent);
        }
    }

    //注册广播
    public void registerBroadcast(){
        if(apkBroadcastReceiver == null){
            apkBroadcastReceiver = new InitializeApkBroadcastReceiver();
        }
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        intentFilter.addDataScheme("package");
        mContext.registerReceiver(apkBroadcastReceiver,intentFilter);
    }

    //取消注册广播
    public void unregisterBroadcast(){
        if(apkBroadcastReceiver != null){
            mContext.unregisterReceiver(apkBroadcastReceiver);
            apkBroadcastReceiver = null;
        }
    }

    //删除apk文件
    public static void removeApkFile(String path){
        File apkFile = new File(path);
        if(apkFile.isFile() && apkFile.exists()){
            apkFile.delete();
        }
    }
}

(2) Crear un receptor de transmisión

        El receptor de transmisión se utiliza para monitorear si el paquete de instalación de la aplicación está instalado, con el fin de eliminar el paquete de instalación.

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class InitializeApkBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())){
            InstallApkUtils.removeApkFile(InstallApkUtils.apkFilePath);
        }
        if(Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())){

        }
        if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())){
            
        }
    }
}

2. Configuración del archivo AndroidManifest.xml

        Agregue permisos y configure nodos de proveedores. El registro de transmisión no se registra estáticamente en este archivo y el código se usa para el registro dinámico, porque la exportación es un paquete de complemento que no se puede registrar de manera efectiva para la aplicación.

(1) Agregar permisos

<uses-permission android:name="android.permission.REPLACE_EXISTING_PACKAGE"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

(2) Configurar el nodo proveedor

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

        Aquí, es necesario asegurarse de que el valor de android:authorities sea consistente con el valor de mContext.getPackageName() + ".fileProvider" en la clase InstallApkUtils, lo cual se puede garantizar usando ${applicationId}.fileProvider.

3. Cree un nuevo archivo de recursos xml

        Cree una nueva ruta de archivo res en el módulo -->src-->main, luego cree una nueva ruta de archivo xml en res y finalmente cree un nuevo archivo file_paths.xml en la carpeta xml y escriba el siguiente contenido.

<?xml version="1.0" encoding="utf-8" ?>
<paths>
    <external-path
        name="apkFiles"
        path="."/>
</paths>

4. Cree el paquete AAR

        Seleccione el módulo, haga clic en Construir-->Crear módulo, o directamente Construir-->Reconstruir proyecto.

        Una vez completada la compilación, el paquete AAR compilado se puede encontrar en el módulo -->build-->outputs-->aar.

3. Llamado a la unidad

1. Colocación del paquete AAR

        Arrastre y suelte el paquete AAR directamente en Activos de Unity-->Complementos-->ruta de Android.

2. Cree un script C# y llame al paquete AAR.

(1) Método de descarga desde el servidor

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class ApplicationStoreManager : MonoBehaviour
{
    //回调
    public delegate void DownloadCallBack();
    public delegate void DownloadCallBack<in T>(T arg);

    public Slider downloadProgressSlider;//下载进度条
    public Text downloadProgressText;//下载进度显示文本
    public Button downloadButton;//下载按钮

    // Start is called before the first frame update
    void Start()
    {
        DownloadButtonAddListener();
    }

    /// <summary>
    /// 从服务器下载文件
    /// </summary>
    /// <param name="url"> 文件地址 </param>
    /// <param name="fileName"> 文件名 </param>
    /// <param name="downloadCallBack"> 回调函数 </param>
    private void DownloadFileFromServer(string url,string fileName,DownloadCallBack<string> downloadCallBack)
    {
        UnityWebRequest request = UnityWebRequest.Get(url);
        StartCoroutine(DownloadFileFromServer(request, fileName, downloadCallBack));
    }

    /// <summary>
    /// 从服务器下载文件协程
    /// </summary>
    /// <param name="unityWebRequest"> UnityWebRequest </param>
    /// <param name="fileName"> 文件名 </param>
    /// <param name="downloadCallBack"> 回调函数 </param>
    /// <returns></returns>
    IEnumerator DownloadFileFromServer(UnityWebRequest unityWebRequest,string fileName,DownloadCallBack<string> downloadCallBack)
    {
        unityWebRequest.SendWebRequest();
        if (unityWebRequest.result == UnityWebRequest.Result.ConnectionError)
        {
            Debug.Log("Download Error:" + unityWebRequest.error);
        }
        else
        {
            //下载进度条显示
            while (!unityWebRequest.isDone)
            {
                downloadProgressSlider.value = unityWebRequest.downloadProgress;
                
                //下载进度转化为百分比数值后保留一位小数
                float progress = Mathf.Round((unityWebRequest.downloadProgress * 100f) * 10f) / 10f;
                downloadProgressText.text = progress.ToString() + "%";
                yield return 0;
            }

            if (unityWebRequest.isDone)
            {
                downloadProgressSlider.value = 1;
                downloadProgressText.text = "100%";
                byte[] results = unityWebRequest.downloadHandler.data;
                string pathUrl = Application.persistentDataPath + "/ApkFile";
                //保存文件
                SavaFile(results, pathUrl, fileName, downloadCallBack);
                //取消下载按钮事件
                downloadButton.GetComponentInChildren<Text>().text = "下载完成";
                downloadButton.onClick.RemoveAllListeners();
            }
        }
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="results"> 下载得到的数据 </param>
    /// <param name="savePath"> 保存路径 </param>
    /// <param name="fileName"> 文件名 </param>
    /// <param name="downloadCallBack"> 回调函数 </param>
    private void SavaFile(byte[] results,string savePath,string fileName,DownloadCallBack<string> downloadCallBack)
    {
        if (!File.Exists(savePath))
        {
            Directory.CreateDirectory(savePath);
        }

        string path = savePath + "/" + fileName;
        FileInfo fileInfo = new FileInfo(path);
        Stream stream;
        stream = fileInfo.Create();
        stream.Write(results, 0, results.Length);
        stream.Close();
        stream.Dispose();
        downloadCallBack(path);
    }

    /// <summary>
    /// 下载按钮添加事件
    /// </summary>
    public void DownloadButtonAddListener()
    {
        downloadButton.onClick.AddListener(delegate ()
        {
            DownloadFileFromServer();
        });
    }

    /// <summary>
    /// 从服务器下载文件
    /// </summary>
    public void DownloadFileFromServer()
    {
        downloadButton.GetComponentInChildren<Text>().text = "下载中...";
        DownloadFileFromServer("http://IP地址及端口/Apk安装包名称.apk", "Apk安装包名称.apk", InstallApk);
    }
}

(2) Método de llamada de la interfaz de Android

        Agregue el siguiente contenido al script ApplicationStoreManager anterior.

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class ApplicationStoreManager : MonoBehaviour
{
    private AndroidJavaObject installApkUtils;

    private void Awake()
    {
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaClass installApkUtilsClass = new AndroidJavaClass("包名.InstallApkUtils");
        installApkUtils = installApkUtilsClass.CallStatic<AndroidJavaObject>("getInstance", currentActivity);
    }

    // Start is called before the first frame update
    void Start()
    {
        installApkUtils.Call("registerBroadcast");
    }

    private void OnDestroy()
    {
        installApkUtils.Call("unregisterBroadcast");
    }

    /// <summary>
    /// 安装Apk
    /// </summary>
    /// <param name="filePath"> Apk文件路径 </param>
    public void InstallApk(string filePath)
    {
        installApkUtils.Call("installApk", filePath);
    }
}

        Registre el receptor de transmisión en el método Start y cancele el registro del receptor de transmisión en el método OnDestroy. El método InstallApk se usa para llamar al método install Apk, que se usa como una devolución de llamada para completar la descarga, y la instalación se llama automáticamente una vez completada la descarga.

3. Servidor de archivos HTTP

        Este proyecto utiliza HFS para crear un servidor de archivos para probar la descarga de archivos de la red. Para más detalles, consulte: sitio web oficial de HFS

        Enlace de descarga de HFS: Descargar

        Después de la descarga, solo hay un archivo exe. Para evitar instalar el archivo, simplemente colóquelo en una ruta adecuada.

        Después de abrir, arrastre y suelte el archivo que desea descargar en Inicio, o arrastre directamente toda la carpeta de almacenamiento de archivos a él, seleccione el archivo que desea descargar y la dirección que se muestra en la parte superior de la ventana es la dirección de descarga. 

4. Configuración del proyecto Unity

        Es muy importante aquí, si no lo configura, no podrá usar Androidx de Android.

(1) Marque la opción interna Configuración de publicación

(2) Modificar el archivo de configuración

        Después de verificar las dos opciones anteriores, se generarán dos archivos, gradleTemplate.properties y mainTemplate.gradle, en la carpeta Activos-->Complementos-->Android del proyecto Unity, y estos dos archivos deben modificarse por separado.

1) Modificar el archivo mainTemplate.gradle

        Agregue una línea de código en el bloque de dependencias: implementación 'androidx.appcompat:appcompat:1.2.0'.

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.2.0'
**DEPS**}

2) Modificar el archivo gradleTemplate.properties

        Agregue lo siguiente al final del archivo:

android.overridePathCheck=true
android.useAndroidX=true
android.enableJetifier=true

5. Diseño UGUI

        Cree un botón, un control deslizante y un texto en el editor de Unity, que se utilizan para vincular el método de descarga, mostrar la barra de progreso de la descarga y mostrar el porcentaje de progreso de la descarga, respectivamente. 

6. Cambie a la plataforma Android, empaquete el apk, instálelo y pruébelo.

4. Entrada de descarga de recursos del paquete AAR

        Si ha leído el tutorial anterior y no sabe cómo usarlo, puede descargar directamente el siguiente paquete AAR y usarlo directamente: contiene el nombre del paquete del complemento, simplemente reemplace el "nombre del paquete". en el script ApplicationStoreManager.

        Instale el Apk en el lado de Android y vuelva a llamar el paquete del complemento AAR cuando se complete la instalación

Supongo que te gusta

Origin blog.csdn.net/qq_40364278/article/details/132321625
Recomendado
Clasificación