[Unity安卓封装][Java版本]APK安装唤醒-非静默版

一.让Unity支持AndroidX

1.1修改mainTemplate.gradle

dependencies中增加implementation 'androidx.core:core:1.0.1'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.core:core:1.6.0'
}

1.2修改gradleTemplate.properties文件支持AndroidX

增加android.useAndroidX=true

org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.useAndroidX=true
android.enableR8=**MINIFY_WITH_R_EIGHT**
unityStreamingAssets=.unity3d**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**

二.配置Manifest和Provider

2.1配置AndroidManifest.xml文件

1.配置安装权限

2.配置provider信息

<?xml version="1.0" encoding="utf-8"?>
<!-- GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN-->
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools">
    <!--请求安装权限-->
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
  <application>
    <activity android:name="com.unity3d.player.UnityPlayerActivity"
                android:theme="@style/UnityThemeSelector">
      <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>
    <!-- FileProvider 配置内容开始 -->
    <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>
    <!-- FileProvider 配置内容结束 -->
  </application>
</manifest>

2.2配置 Provider文件

在Plugins/Android/res/下创建xml文件夹以及file_paths.xml文件,此处文件名要和AndroidManifest配置的文件名一一对应。

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <!--取决于你APK的缓存位置-->
    <files-path name="files" path="."/>
</paths>

三.导入Java代码

将java代码放置Plugins/Android/Java中 

3.1ApkUtility.java

用于给Unity暴露接口

package cn.ktgames.utility.android;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.FragmentManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;

import androidx.core.content.FileProvider;

import java.io.File;

public class ApkUtility {
    /**
     * 安装失败Apk不存在
     */
    private static final int InstallFailWithFileNon = 10001;
    /**
     * 安装失败用户取消授权
     */
    private static final int InstallFailWithUserCancelInstallPermission = 10002;

    /**
     * Apk工具监听器
     */
    public interface Listener{
        void onInstallResult(int code,String path,String message);
    }

    private static String ApplyPermissionTitle = "请设置本应用安装权限";
    private static String ApplyPermissionApplyButton = "前往设置";
    private static String ApplyPermissionCancelButton = "取消设置";

    private static Listener listener;

    /**
    * 初始化
    */
    public static void Init(Listener lis)
    {
        listener = lis;
    }

    /**
     * 设置权限申请信息
     * @param title 标题
     * @param applyButton 同意按钮文本
     * @param cancelButton 取消按钮文本
     */
    public static void SetApkPermissionInfo(String title,String applyButton,String cancelButton){
        ApplyPermissionTitle = title;
        ApplyPermissionApplyButton = applyButton;
        ApplyPermissionCancelButton = cancelButton;
    }

    /**
     * 发送安装结果
     * @param code 代码
     * @param path 文件路径
     * @param message 消息内容
     */
    private  static void SendInstallResult(int code,String path,String message){
        if (listener!=null)
        {
            listener.onInstallResult(code,path,message);
        }
    }

    /**
     * 通过路径安装APK
     * @param activity Activity
     * @param filePath 文件路径
     */
    public static void InstallApk(Activity activity, String filePath){
        File file = new File(filePath);
        if (!file.exists()){
            SendInstallResult(InstallFailWithFileNon,filePath,"File Non-Existent");
            return;
        }
        //8.0+系统
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //获取系统安装权限
            boolean isInstallPermission = GetInstallPermission(activity);
            if (isInstallPermission){
                InstallApk(activity,file);
            }else{
                activity.runOnUiThread(new Runnable(){
                    public void run() {
                        ApplyPermission(activity,filePath);
                    }
                });
            }
        }
        else {
            InstallApk(activity,file);
        }
    }

    /**
     * 安装Apk
     * @param activity Activity
     * @param file 目标文件
     */
    private static void InstallApk(Activity activity,File file)
    {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        //7.0+系统,需要配置FileProvider应用文件共享
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
            //这里注意fileProvider要和manifest的authorities保持一致
            Uri apkUri = FileProvider.getUriForFile(activity, GetPackageName(activity)+".fileProvider", file);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        }
        //7.0-系统
        else {
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Uri uri = Uri.fromFile(file);
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
        }
        activity.startActivity(intent);
    }

    /**
     * 获取包名
     * @param context Context
     * @return 包名,这里返回的时applicationid
     */
    private static String GetPackageName(Context context){
        return context.getPackageName();
    }

    /**
     * 获取安装权限
     * @param activity Context
     * @return 是否拥有安装权限
     */
    public static boolean GetInstallPermission(Context activity){
        return activity.getPackageManager().canRequestPackageInstalls();
    }

    private static AlertDialog.Builder permissionDialog;

    /**
     * 申请安装权限
     * @param activity
     * @param filePath
     */
    private static void ApplyPermission(Activity activity, String filePath){
        permissionDialog = new AlertDialog.Builder(activity);
        permissionDialog.setTitle(ApplyPermissionTitle);
        permissionDialog.setCancelable(false);
        permissionDialog.setNegativeButton(ApplyPermissionApplyButton, (dialog, which) -> {
            ApkUtilityFragment fragment = GetFragment(activity);
            Uri packageUri = Uri.parse("package:"+ GetPackageName(activity));
            Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,packageUri);
            fragment.StartActivityForResult(intent, ApkUtilityFragment.REQCODE_PERMISSION_INSTALL, (requestCode, resultCode, data) -> {
                InstallApk(activity,filePath);
            });
        });
        permissionDialog.setPositiveButton(ApplyPermissionCancelButton, (dialog, which) -> SendInstallResult(InstallFailWithUserCancelInstallPermission,filePath,"User Cancel Install Permission"));
        permissionDialog.show();
    }
    private static ApkUtilityFragment apkUtilityFragment;

    /**
     * 获取或创建Fragment
     * @param activity
     * @return
     */
    private static ApkUtilityFragment GetFragment(Activity activity)
    {
        if (apkUtilityFragment==null)
        {
            FragmentManager fragmentManager = activity.getFragmentManager();
            apkUtilityFragment =(ApkUtilityFragment)fragmentManager.findFragmentByTag(ApkUtilityFragment.TAG);
            if (apkUtilityFragment==null){
                apkUtilityFragment = new ApkUtilityFragment();
                apkUtilityFragment.SetActivity(activity);
            }
        }
        return apkUtilityFragment;
    }
}

3.2ApkUtilityFragment

用于状态接收,处理

package cn.ktgames.utility.android;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.util.SparseArray;

public class ApkUtilityFragment extends Fragment {
    /**
     *Fragment 标签
     */
    public static final String TAG = "on_ktgames_action_apk_utility_fragment";
    /**
     * 安装权限请求码
     */
    public static final int REQCODE_PERMISSION_INSTALL = 100411;
    /**
     * ActivityResult 返回回调接口
     */
    public interface ActivityResult{
        /**
         * ActivityResult 返回回调
         */
        void onActivityResult(int requestCode, int resultCode, Intent data);
    }
    /**
     * 依赖的Activity
     */
    private Activity activity;
    /**
     * 设置依赖的Activity
     */
    public void SetActivity(Activity activity){
        //获取Fragment管理器
        FragmentManager fragmentManager = activity.getFragmentManager();
        this.activity =activity;
        fragmentManager
                .beginTransaction()//开始操作
                .add(this, ApkUtilityFragment.TAG)//添加fragment
                .commitAllowingStateLoss();//提交(此方法会有丢失页面状态信息的风险。)
        fragmentManager.executePendingTransactions();//立刻执行transaction的动作
    }
    /**
     * 用于缓存跳转回调结果
     */
    private SparseArray<ActivityResult> activityResults = new SparseArray<ActivityResult>();
    /**
     * 执行一个Activity跳转
     */
    public void StartActivityForResult(Intent intent,int requestCode,ActivityResult result){
        activityResults.put(requestCode,result);
        startActivityForResult(intent,requestCode);
    }
    /**
     * 接收Activity结果
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        ActivityResult callback = activityResults.get(requestCode);
        activityResults.remove(requestCode);
        if (callback != null) {
            callback.onActivityResult(requestCode,resultCode,data);
        }
    }
}

 四.编写C#接口

using System;
using UnityEngine;

namespace Cn.Ktgames.Util.Android
{
    /// <summary>
    /// APK工具
    /// </summary>
    public class ApkUtility
    {
        /// <summary>
        /// 安装失败Apk不存在
        /// </summary>
        public const int InstallFailWithFileNon = 10001;
        /// <summary>
        /// 安装失败用户取消授权
        /// </summary>
        public const int InstallFailWithUserCancelInstallPermission = 10002;
        /// <summary>
        /// 安装结果
        /// </summary>
        public static Action<int, string, string> onInstallResult;

        class ApkUtilityListener : AndroidJavaProxy
        {
            public ApkUtilityListener() : base(ClassName + "$Listener") { }
            void onInstallResult(int code, string path, string message)
            {
                ApkUtility.onInstallResult?.Invoke(code, path, message);
            }
        }
        private const string PackageName = "cn.ktgames.utility.android";
        private const string ClassName = PackageName +".ApkUtility";

        private static AndroidJavaObject activity;
        private static AndroidJavaClass utillityClass; 
        private static AndroidJavaClass UtillityClass
        {
            get
            {
                if(utillityClass==null)
                {
                    utillityClass = new AndroidJavaClass(ClassName);
                }
                return utillityClass;
            }
        }
        /// <summary>
        /// 初始化,如果想接收安装回调结果先调用此接口
        /// </summary>
        public static void Init()
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            UtillityClass.CallStatic("Init",new ApkUtilityListener());
#endif
        }

        /// <summary>
        /// 安装Apk
        /// </summary>
        /// <param name="filePath"></param>
        public static void InstallApk(string filePath)
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            UtillityClass.CallStatic("InstallApk", GetActivity(), filePath);
#endif
        }
        /// <summary>
        /// 设置权限弹窗信息
        /// </summary>
        /// <param name="title"></param>
        /// <param name="applyButton"></param>
        /// <param name="cancelButton"></param>
        public static void SetApkPermissionInfo(string title, string applyButton, string cancelButton)
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            UtillityClass.CallStatic("SetApkPermissionInfo", title, applyButton, cancelButton);
#endif
        }
        /// <summary>
        /// 获取是否有安装权限
        /// </summary>
        public static bool GetInstallPermission()
        {
#if UNITY_ANDROID && !UNITY_EDITOR
            return UtillityClass.CallStatic<bool>("GetInstallPermission", GetActivity());
#else
            return false;
#endif
        }
        /// <summary>
        /// 获取Activity
        /// </summary>
        /// <returns></returns>
        private static AndroidJavaObject GetActivity()
        {
            if (activity==null)
            {
                var UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
                activity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            }
            return activity;
        }
    }
}

五.测试工程

https://download.youkuaiyun.com/download/l100142548/85072296https://download.youkuaiyun.com/download/l100142548/85072296

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值