美文网首页
Android 应用下载、更新、安装、卸载、启动

Android 应用下载、更新、安装、卸载、启动

作者: 洒一地阳光_217d | 来源:发表于2020-08-16 13:56 被阅读0次

参考链接:Android Studio打包arr包并导入Unity中
参考链接:Unity中调用Android方法
参考链接:Unity中获取本地应用图标Icon

有的需求,App中需要一个应用商店,那就涉及到了应用下载、更新、安装、卸载、启动等。

一 、Android 中java代码,提供安装、启动、卸载、删除APK包功能:
package com.android.util;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;

import java.io.File;

import androidx.core.content.FileProvider;

public class UseForUnity {

    /// 设置一个 Activity 参数
    private static Activity _unityActivity;

    // 通过反射获取 Unity 的 Activity 的上下文

    public static Activity getActivity() {

        if (null == _unityActivity) {
            try {
                Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
                Activity activity = (Activity) classtype.getDeclaredField("currentActivity").get(classtype);
                _unityActivity = activity;
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }

        return _unityActivity;
    }

    // 获取安卓版本
    public static int getAndroidVersion() {
        return android.os.Build.VERSION.SDK_INT;
    }

    // 判断应用是否安装成功
    public boolean isAppInstalled(String packageName) {
        return isAppExist(packageName);
    }

    // 判断应用是否卸载成功
    public boolean isAppRemoved(String packageName) {
        return !isAppExist(packageName);
    }

    // 判断应用是否存在
    private boolean isAppExist(String packageName) {
        PackageInfo packageInfo;
        try {
            packageInfo = getActivity().getPackageManager().getPackageInfo(packageName, 0);
        } catch (PackageManager.NameNotFoundException e) {
            packageInfo = null;
            e.printStackTrace();
        }

        if (packageInfo == null) {
            return false;
        } else {
            return true;
        }
    }

    // 安装apk,兼容SDK24(安卓7.0)以上和以下
    public void installPackageByName(String pakageName) {
        File file = new File(pakageName);
        if(!file.exists()){
            return ;
        }
        // 文件uri
        Uri uri = null;
        Intent intent = new Intent(Intent.ACTION_VIEW);

        if(android.os.Build.VERSION.SDK_INT>= android.os.Build.VERSION_CODES.N) {
            // SDK版本>=24, 安卓7.0以上
            uri = FileProvider.getUriForFile(getActivity(),"com.tvbox.yoostore"+".fileprovider",file);
            // 添加读写权限
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        }else{
            // SDK版本<24, 安卓7.0以下
            uri= Uri.fromFile(file);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");//设置intent的数据类型
        getActivity().startActivity(intent);
    }

    // 启动apk
    public void openPackageByName(String pakageName) {
        PackageManager pm = getActivity().getPackageManager();
        Intent i = pm.getLaunchIntentForPackage(pakageName);//获取启动的包名
        getActivity().startActivity(i);
    }

    // 卸载apk
    public void deletePackageByName(String pakageName) {
        Uri uri = Uri.fromParts("package", pakageName, null);
        Intent intent = new Intent(Intent.ACTION_DELETE, uri);
        getActivity().startActivity(intent);
    }

    /**
     * 删除单个文件
     *
     * @param filePath 被删除文件的文件名
     * @return 文件删除成功返回true,否则返回false
     */
    public boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.isFile() && file.exists()) {
            return file.delete();
        }
        return false;
    }
}
二、然后Unity工程中去下载,调用写好的安卓方法:

下载功能:

    /// <summary>
    /// 下载安装包
    /// </summary>
    public class DownloadApk
    {
        public enum DownloadApkState
        {
            HeadRequest,
            BodyRequest,
            FinishRequest,
            Completed,
        }

        public bool isDone { get; private set; }

        public DownloadApkState state { get; private set; }

        /// <summary>
        /// 下载进度回调
        /// </summary>
        private Action<string, float> _onProgress;

        /// <summary>
        /// 下载完成回调
        /// </summary>
        private Action _onCompleted;

        /// <summary>
        /// 下载进度
        /// </summary>
        private float _progress;

        /// <summary>
        /// 要下载的应用包名
        /// </summary>
        private string _packageName;

        /// <summary>
        /// 下载url
        /// </summary>
        private string _url;

        // 如:Application.persistentDataPath + "/" + appName + versionCode + ".apk";
        /// <summary>
        /// 保存路径
        /// </summary>
        private string _savePath;

        private UnityWebRequest request;

        private FileStream fs;

        private long _len; 

        private int _index;

        private long _maxlen;

        private string _error;

        public DownloadApkState(string url, string packageName, string savePath, string onProgress, string onCompleted)
        {
            _url = url;
            _packageName = packageName;
            _savePath = savePath;
            _onProgress = onProgress;
            _onCompleted - onCompleted;
        }

        /// <summary>
        /// 开始下载
        /// </summary>
        public void Start()
        {
            request = UnityWebRequest.Head(_url);
            request.SendWebRequest();
            _progress = 0;
            isDone = false;
        }

        /// <summary>
        /// 取消下载
        /// </summary>
        public void Cancle()
        {
            if (fs != null)
            {
                fs.Close();
                fs.Dispose();
            }
            isDone = true;
        }
        
        void WriteBuffer()
        {
            var buff = request.downloadHandler.data;
            if (buff != null)
            {
                var length = buff.Length - _index;
                fs.Write(buff, _index, length);
                _index += length;
                _len += length;
                _progress = _len / (float)_maxlen;
                _onProgress?.Invoke(_packageName, _onProgress);
            }
        }

        public void Update()
        {
            if (isDone)
            {
                return;
            }

            switch (state)
            {
                case DownloadApkState.HeadRequest:
                    if (request._error != null)
                    {
                        _error = request._error;
                    }

                    if (request.isDone)
                    {
                        _maxlen = long.Parse(request.GetResponseHeader("Content-Length"));
                        request.Dispose();
                        request = null;
                        var dir = Path.GetDirectoryName(_savePath);
                        if (!Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        if (FileTool.ExistsFile(_savePath))
                        {
                            FileTool.DeleteFile(_savePath);
                        }
                        fs = new FileStream(_savePath, FileMode.OpenOrCreate, FileAccess.Write);
                        _len = fs.Length;
                        if (_len < _maxlen)
                        {
                            fs.Seek(_len, SeekOrigin.Begin);
                            request = UnityWebRequest.Get(_url);
                            request.SetRequestHeader("Range", "bytes=" + _len + "-" + _maxlen);
                            request.SendWebRequest();
                            _index = 0;
                            state = DownloadApkState.BodyRequest;
                        }
                        else
                        {
                            // 下载完成
                            state = DownloadApkState.FinishRequest;
                        }
                    }
                    break;

                case DownloadApkState.BodyRequest:
                    if (request._error != null)
                    {
                        _error = request._error;
                        LWDebug.Log(_error);
                    }

                    if (!request.isDone)
                    {
                        WriteBuffer();
                    }
                    else
                    {
                        WriteBuffer();
                        if (fs != null)
                        {
                            fs.Close();
                            fs.Dispose();
                        }
                        request.Dispose();

                        // 下载完成
                        state = DownloadApkState.FinishRequest;
                    }
                    break;

                case DownloadApkState.FinishRequest:
                    // 下载完成,调用完成回调
                    isDone = true;
                    _onCompleted?.Invoke();
                    state = DownloadApkState.Completed;
                    break;
            }
        }
    }

下载完成后,调用刚刚写好的Android安装方法,也可以直接调用Android原生方式安装:

    /// <summary>
    /// 安装apk
    /// </summary>
    public static bool InstallApp(string apkPath)
    {
        //判断安卓7.0以下
        if (AndroidSDKVersion() < 24)
        {
            LWDebug.Log("低版本24以下(安卓7.0)安装");
            return InstallAppLowAPI(apkPath);
        }
        else
        {
            LWDebug.Log("高版本24以上(安卓7.0)安装");
            return InstallAppHighAPI(apkPath);
        }
    }

    /// <summary>
    /// 获取安卓SDK版本号
    /// </summary>
    /// <returns></returns>
    private static int GetAndroidSDKVersion()
    {
        int version = 0;
        AndroidJavaObject androidJavaObject = new AndroidJavaObject("com.android.util.UseForUnity");
        version = androidJavaObject.CallStatic<int>("getAndroidVersion");
        return version;
    }

    /// <summary>
    /// 低版本安装
    /// </summary>
    /// <param name="apkPath"></param>
    /// <returns></returns>
    private static bool InstallAppLowAPI(string apkPath)
    {
        bool success = true;
        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);

            //安装成功
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
            //安装失败
            success = false;
        }
        return success;
    }

    /// <summary>
    /// 24以上(安卓7.0)安装
    /// </summary>
    /// <param name="apkPath"></param>
    /// <returns></returns>
    private static bool InstallAppHighAPI(string apkPath)
    {
        bool success = true;
        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");

            AndroidJavaObject fileObj = new AndroidJavaObject("java.io.File", apkPath);
            AndroidJavaClass fileProvider = new AndroidJavaClass("android.support.v4.content.FileProvider");
            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);

            //安装成功
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
            //安装失败
            success = false;
        }

        return success;
    }

检查App是否存在,可以调用刚刚写好的Android方法,也可以直接调用Android原生方法:

    /// <summary>
    /// 检查应用是否存在
    /// </summary>
    /// <param name="packageName"></param>
    /// <returns></returns>
    public static bool IsAppExits(string packageName)
    {
        AndroidJavaClass up = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject currentActivity = up.GetStatic<AndroidJavaObject>("currentActivity");
        AndroidJavaObject packageManager = currentActivity.Call<AndroidJavaObject>("getPackageManager");
        AndroidJavaObject packageInfos = packageManager.Call<AndroidJavaObject>("getInstalledPackages", 0);
        AndroidJavaObject[] packages = packageInfos.Call<AndroidJavaObject[]>("toArray");
        for (int i = 0; i < packages.Length; i++)
        {
            AndroidJavaObject applicationInfo = packages[i].Get<AndroidJavaObject>("applicationInfo");
            // 判断是不是系统应用 0:不是系统应用,1:是系统应用
            if ((applicationInfo.Get<int>("flags") & applicationInfo.GetStatic<int>("FLAG_SYSTEM")) == 0)
            {
                string pkgName = applicationInfo.Get<string>("packageName");
                if (pkgName == packageName)
                {
                    return true;
                }
            }
        }
        return false;
    }
三、项目设置:

包名设置,以com.chen.ttt为例:
1、Plugins/Android/res/xml下的provider_paths.xml中path的后面com.chen.ttt换成包名;

2、BulidConfig.xml中的applicationIdentifier的com.chen.ttt换成包名;

3、xml设置,示例:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.chen.ttt" 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.chen.ttt.fileprovider" android:exported="false" android:grantUriPermissions="true">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" />
    </provider>
    <meta-data android:name="platform_high" android:value="1" />
  </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>

相关文章

网友评论

      本文标题:Android 应用下载、更新、安装、卸载、启动

      本文链接:https://www.haomeiwen.com/subject/ejytjktx.html