zoukankan      html  css  js  c++  java
  • Unity 大版本更新之APK的下载与覆盖安装

      作为一个游戏开发者,更新这个技能是必不可少的!更新分为游戏内的更新,也就是所谓的资源热更包括AssetBundle更新和代码更新,代码其实也是所谓的二进制文件,在安卓上和普通资源文件毫无差异,然而在IOS上差别大来个去了,由于苹果爸爸所谓出于安全性的考虑,不支持JIT,我们也很无奈啊! 如今能绕过去的,只能靠解释器去执行这部分被视为另类的代码文件了,能解决的也就是今天各种版本的Lua和ILRuntime了!好了,夜已深,废话不多说了,开始今天正题!!!

    1,如何通过Unity进行应用内更新?

      应用内的更新也就所谓的资源热更了,从CDN上直接下载就完事了,下载的方式有很多,WWW,WebRequest,HttpWebRequest等,最不推荐的就是WWW,原因一: www.bytes这家伙很占内存,句柄有限,在IOS上文件过多,开的WWW超过句柄限制会有意想不到的惊喜(Bug),Unity官方已逐渐适应WebRequest取而代之了,推荐使用HttpWebRequest,支持断点续传,很是方便!

    2,何时进行大版本更新,该如何更新呢?

      这个大版本更新要看如何设计了,我们游戏是采用高中低三位来决定该更新哪些东西,例如:当前版本号1.0.1,下次客户端提高版本号到1.0.2或者1.1.0都是资源更新,如果大版本好改为2.x.x则进行大版本更新,如何更新呢?两种方法,一通过"market://details?id=com.xxx.xxx"标记使用Android代码打开应用市场内的应用,那么有经验同学就看到了问题,如果我装的不是本应用商店的应用呢,那不就凉了!!!是的,装的不是手机应用商店的肯定凉不了啊,我们还有方法二呢,前往你下载的对应版本的cdn上直接下载就可以了啊!至于怎么下载请转到1.

    3,下载完了,我该怎么安装呢?

      不要着急,安装及其的简单,Android原生提供了很好API,如果你的Android OS低于7.0那么只需要这几行代码就OK了!

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        File apkFile = new File(apkFullPath);
        Uri uri = null; uri = Uri.fromFile(apkFile);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        MainActivity.instance.startActivity(intent);

      为什么我强调了下是7.0的呢,因为Android 7.0 行为变更了所以这么写会报错的,尝试传递 file://URI可能会触发FileUriExposedException。不要慌,那么如何解决呢?我们首先需要在 AndroidManifest里添加 provider 标签,通过这个标签将apk所在路径的share出去,这样本次就能访问该路径下的apk了,那么这个错误也就引刃而解了!如何使用这个provider呢,别着急,手把手教你如何使用provider。

    第一步:先在AndroidManfiest.xml添加provider标签,位置在 application内即可!

        <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.wuzhang.testandroid.fileProvider"
                android:grantUriPermissions="true"
                android:exported="false">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths" />
          </provider>

    别忘记还要加个安装的权限: <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> 

    第二步:指定共享目录,在res下创建/xml/provider_paths.xml,路径见下图

    provider_paths.xml文件

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

    解释下,此处name="publicDir"无实际意义,就是一个解释而已,path=“”;表示的是这个目录是当前根目录下的不再添加子目录等价于Unity中的Application.persistentDataPath也就是安卓设备上的storage/0/android/data/com.wuzhang.testandroid/files/

    第三步:再次调用apk安装代码

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        File apkFile = new File(apkFullPath);
        Uri uri = null;
        String path = MainActivity.instance.getApplicationContext().getPackageName() + ".fileProvider";
        uri = FileProvider.getUriForFile(MainActivity.instance, path,apkFile);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        MainActivity.instance.startActivity(intent);
    

    PS:这里有个地方需要注意,为何非要是这个顺序???

    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

      ...

      ...

    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

    为什么setFlag放到上面就可以,addFlag放上面就不行呢???原因很简单,当setFlag时会先清空intent下之前所有的flag,所以addFlag的FLAG_GRANT_READ_URI_PERMISSION就无效了,本人亲自踩的坑,多么痛的礼物!

    这一切到搞定了,打包真机测试,android 7.0的果然好了,年轻人,别高兴的太早,说完又遇到一个坑,8.0以上的系统死活不会弹出安装界面,一首凉凉送给自己,,,但是马上就要看到胜利的曙光了,一定要淡定,车到山前必有路,办法总比困难多!!!

    最终安装代码,完美兼容,Android 7.0,8.0

    public static void installApk(String apkFullPath)
    {
        try
        {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            Log.v("android", apkFullPath);
            onCoderReturn(apkFullPath);
            File apkFile = new File(apkFullPath);
            Uri uri = null;
            if (Build.VERSION.SDK_INT >= 24)
            {
                String path = MainActivity.instance.getApplicationContext().getPackageName() + ".fileProvider";
                Log.v("android", path);
                uri = FileProvider.getUriForFile(MainActivity.instance, path, apkFile);
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }
            else
            {
                uri = Uri.fromFile(apkFile);
                Log.v("android", apkFile.getAbsolutePath());
            }
            onCoderReturn("install" + uri.getPath());
            intent.setDataAndType(uri, "application/vnd.android.package-archive");
            //解决安卓8.0安装界面不弹出
            //查询所有符合 intent 跳转目标应用类型的应用,注意此方法必须放置在 setDataAndType 方法之后
            List<ResolveInfo> resolveLists = MainActivity.instance.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
            // 然后全部授权
            for (ResolveInfo resolveInfo : resolveLists)
            {
                String packageName = resolveInfo.activityInfo.packageName;
                MainActivity.instance.grantUriPermission(packageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            }
            MainActivity.instance.startActivity(intent);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    好了,到此基本上真的结束了,还有一个可优化的是安装完成可以做个自动启动app就完美了,这个有时间继续完善!时间过得好快1点开始写的,现在都快3点半了,困的不行了,得睡觉了,祝大家小长假玩的愉快,有问题可以联系我一起探讨!


  • 相关阅读:
    JavaScript系列---【分析局部作用域下的预解析】
    javaScript系列---【分析全局作用域下的预解析】
    javaScript系列---【分析函数的arguments】
    JavaScript系列---【条件if--切换图片案例2 高亮及按钮同步显示】
    javaScript系列---【this详解及call和apply修改this指向】
    JavaScript系列---【选项卡案例】
    JavaScript系列---【QQ列表展开及闭合案例】
    系统安装01-CentOS6系统安装
    hdoj--3635--Dragon Balls(并查集记录深度)
    hdoj--1281--棋盘游戏(最小点覆盖+枚举)
  • 原文地址:https://www.cnblogs.com/wuzhang/p/wuzhang20190405.html
Copyright © 2011-2022 走看看