美文网首页
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