您当前的位置: 首页 >  unity

幻世界

暂无认证

  • 3浏览

    0关注

    237博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【unity开发小技巧】Unity内部安装更新App三种方案(安卓APk)

幻世界 发布时间:2019-08-01 15:50:57 ,浏览量:3

欢迎加入Unity业内qq交流群:956187480

qq扫描二维码加群

方案1:

因为公司U3D项目在立项之初都没有能做好热更新的规化,导致现在要去做U3D的热更新非常难,并且项目已处于中后期,大部分的方案不管是用反射(DLL反射更新),还是用Lua,都需要把项目大部分代码结构推倒重来。于是就放弃热更新,选择还是直接用Apk来更新游戏。

在开始之前先是在网上查了很多资料,但是能够让我等初级开发者能够顺手就能用的基本没有,再加上我们很多Unity开发者对Android和Ios的原生开发都不了解,就导致上手困难。今天在这里尽量详细记录。

1.apk上传和下载

将工程中StreamingAssets这个目录下的文件全部清空,然后再用Unity打包一个APK。把APK文件上传至服务器,用www下载到指定路径即可,至于为啥要清空StreamingAssets,是因为我的项目资源是用ab包加载的,在第一次安装的时候都已经释放的本地了,如果更新版本没有资源更新就清空即可,如果有资源更新就不能清空。正常应该做资源ab包的热更新,这个有时间再给大家分享。

public IEnumerator InstallApk()
    {
        WWW www = new WWW("http://192.168.10.100/down/android/demo/demo.apk");
        //下载需要更新的apk
        while (true)
        {
            Debug.Log(www.progress / 1f * 100);
            if (www.isDone)
            {
                break;
            }
            yield return null;
        }
        if (!string.IsNullOrEmpty(www.error))
        {
            Debug.Log("error:" + www.error);
            yield return 0;
        }
            //将apk写入沙盒目录
            string path = Application.persistentDataPath + "/test.apk";
            File.WriteAllBytes(path, www.bytes);
    }

拷贝APK安装路径Application.dataPath的asset目录文件到可读写目录Application.persistentDataPath

下载到指定路径后就需要在程序内部调用安装。需要跟android交互调用原生方法。

2.Unity跟Android交互

参考之前的博客:Unity调用安卓原生的通用前奏(血泪史)

3.核心代码

安卓端:判断安卓版本7.0是分水岭

   public void InstallApk(String apkPath) {
        System.out.println("Android下载地址:"+apkPath);
        File file = new File(apkPath);
        Intent intent = new Intent(Intent.ACTION_VIEW);

        if(Build.VERSION.SDK_INT>=24) { //Android 7.0及以上
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            // 参数2 清单文件中provider节点里面的authorities ; 参数3  共享的文件,即apk包的file类
            Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID+".fileprovider", file);//记住修改包名
            //对目标应用临时授权该Uri所代表的文件
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        }else{
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        this.startActivity(intent);
    }

Unity端:上面已经下载更新包到指定路径了直接调用安装就行

   using (AndroidJavaClass cl = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
            {
                using (AndroidJavaObject ob = cl.GetStatic("currentActivity"))
                {
                    //然后调用android来安装apk
                    ob.Call("InstallApk", path);
                }
            }

这个安装会覆盖掉之前安装的APK,由于这个APK里asset目录是空的,所以覆盖之后也就没有asset了,这也是为什么要做第一步的原因。另外,这个Application.persistentDataPath+filename 在Java端调用的时候,需要在路径最前面添加”file://”。这里强调一下,重新安装APK后,Application.persistentDataPath和WWW.LoadFromCacheOrDownload缓存的文件,是不会被覆盖的,所以请放心覆盖原来的APK。

4.注意

有个权限问题:三步走

最后在安卓端需要加个V4依赖,我会把v4包也在工程里给到大家。添加依赖的方法很简单。另外因为我安卓的目标版本是8.1,所以上面那个7.0的逻辑判断我没有验证7.0一下的需要大家注意。博客记录起来很容易,但是在真正的操作中会遇到很多各种各样的问题,特别是android的api版本还有Tool版本跟unity项目的冲突问题。只有当你遇到了你才能体会,不过话说回来当你都给解决掉的时候就说明水平上升了。

方案2:

因为是 vr项目,工程内部接入的第三方的sdk已经整合过安卓,如果按照以上方案下载的话因为MainActivity的冲突在vr一体机息屏再次亮屏的话就会黑屏。原因是两个Mainactivity加载顺序导致的。后来选择另外一种方案,弱化跟安卓的交互,直接在unity内调用下载。

1.代码:

public void InstallAPK(string path)
    {
        try
        {
            var FileProvider = new AndroidJavaClass("android.support.v4.content.FileProvider");
            var Intent = new AndroidJavaClass("android.content.Intent");
            var ACTION_VIEW = Intent.GetStatic("ACTION_VIEW");
            var FLAG_ACTIVITY_NEW_TASK = Intent.GetStatic("FLAG_ACTIVITY_NEW_TASK");
            var FLAG_GRANT_READ_URI_PERMISSION = Intent.GetStatic("FLAG_GRANT_READ_URI_PERMISSION");
            var intent = new AndroidJavaObject("android.content.Intent", ACTION_VIEW);
            var UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
            var currentActivity = UnityPlayer.GetStatic("currentActivity");

            var file = new AndroidJavaObject("java.io.File", path);
            var uri = FileProvider.CallStatic("getUriForFile", currentActivity, "包名.fileprovider", file);
            intent.Call("setFlags", FLAG_ACTIVITY_NEW_TASK);
            intent.Call("addFlags", FLAG_GRANT_READ_URI_PERMISSION);
            intent.Call("setDataAndType", uri, "application/vnd.android.package-archive");

            currentActivity.Call("startActivity", intent);
        }
        catch (System.Exception e)
        {
            Debug.LogError(e.Message);
        }
    }

 2.清单文件添加:

 
      
    

3. 新建xml文件,参考方案1,可以从安卓拖进unity,也可以直接在unity创建

方案3:

应该是还有一种方案,直接在安卓端创建新的activity不继承unityactivity的。然后打jar或者arr包在unity内部直接调用。

参考:unity 中启动Android activity_u013341672的博客-CSDN博客,没看太懂,测试了也无效

安卓端代码:

public class Battery {
    public static void Oninit(Object s){
        Context context;
        context = (Context) s;
        Intent intent =new Intent();
        intent.putExtra("my","123");
        intent.setClass(context,com.pico.Integration.MyActivity.class);
        context.startActivity(intent);
    }
}
public class MyActivity extends Activity {
    public void InstallApk(String apkPath) {
        System.out.println("Android下载地址:"+apkPath);
        File file = new File(apkPath);
        Intent intent = new Intent(Intent.ACTION_VIEW);

        if(Build.VERSION.SDK_INT>=24) { //Android 7.0及以上
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            // 参数2 清单文件中provider节点里面的authorities ; 参数3  共享的文件,即apk包的file类
            Uri apkUri = FileProvider.getUriForFile(getApplicationContext(), BuildConfig.APPLICATION_ID+".fileprovider", file);//记住修改包名
            //对目标应用临时授权该Uri所代表的文件
            intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
        }else{
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        this.startActivity(intent);
    }
}

 Unity端代码:调用应该是有问题的Oninit方法可以执行,但是MyActivity里面的InstallApk方法调不到,后面就没有再研究,大家可以深入一下

  AndroidJavaObject ob = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic("currentActivity");
            AndroidJavaObject ajo = new AndroidJavaClass("包名.Battery");

            ajo.CallStatic("Oninit", ob);
           
           // ajo.Call("InstallApk", path);
            ob.Call("InstallApk", path);

欢迎加入Unity业内qq交流群:956187480

qq扫描二维码加群

关注
打赏
1660704426
查看更多评论
立即登录/注册

微信扫码登录

0.0403s