Unity逻辑热更新 Unity调用安卓实现apk更新 -白羽

今天做的分享是Unity逻辑(半热乎)更新


2019.11.5日


本篇文章更像一个导航性文章,其中会有一些链接的引用,将各个博主所长引用并串联起来,帮你实现逻辑更新。

谁需要看我:
  1. 项目前期没有规划热更新方案,到了中后期需要进行代码更新,但又苦于做lua或者反射机制热更新的团队。
  2. 项目体量不大,对更新体验要求并非十分严格的项目。(由于更新过程会弹出安卓提示框,进行apk安装,因此用户体验并没有热更新那么完美)
  3. 需要一天之内出上线版本,但从没有做过类似功能模块,且不了解Unity和android体系交互更新方式的朋友。(如果你去网上找会发现,方案一大堆,一个也用不了。)
我可以为你做什么:

1,细致如对小白般的教你如何从0撸出一套unity android交互更新方案。

2,30分钟包学会Unity打包apk的逻辑更新。

3,及时反馈留言问题,如果有需要可以QQ联系帮你解答,QQ全天在线。你也许可以从本文学到一些学习的理念。


正文

什么叫“半热”更新呢?

即:在不使用lua和ilrtime的基础上,尽量减少用户更新成本,提升体验。实现逻辑更新。(这并不是一个完美的更新方式,推荐攒时间学习ILruntime,但如果你时间很紧,那就继续看吧。)

  • 更新流程:
    简单来说: 下载新版本apk,实现unity和安卓交互,调用安卓方法。在安卓方法中安装相应apk。
    具体流程:
    首先在程序开始时,我们可以选择调用版本检测逻辑进行服务器版本对比,当对比结果显示服务器版本高于本地,则执行更新:
    1,下载新apk。2,保存到安卓本地(Unity中的persistentdatapath下)3,调用安卓代码,执行apk安装。

对于一个两年左右的开发人员来说,版本检测和资源下载本地存储并不难。但是如果没有接触过Android开发的话,直接上手去撸安卓代码,并实现apk的安装,是一个难点。

所以,如果不会进行版本检测和资源下载和本地存储的,可以联系我QQ 1042017370,我会简单的跟你讲实现逻辑以及解答你的问题。或者百度UnityWebRequest的用法,进行自主学习。


当你可以完整的实现版本检测,新版本的下载和本地存储的时候,我们就可以看一下第一个难点了:

unity与安卓交互

在搜索了大量相关文章后,推荐 Pieces_Jing 在简书上的交互方案。这里做一个引用,贴上链接:https://www.jianshu.com/p/86b275da600e

当你花15分钟跟随以上链接进行实际测试后,应该已经掌握了利用java反射机制进行unity 安卓交互了。
那么,这个时候恭喜你,只需要在学会一点就可以实现我们的主体功能了,但是别掉以轻心,不然是会不小心掉坑的。

安卓代码安装apk

代码上非常简单,取自https://blog.csdn.net/male09/article/details/78621183 (感谢!合十)
如果你的unity打包目标平台是安卓7.0以前,就只有一下这些:

 Intent install = new Intent(Intent.ACTION_VIEW);
            install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
            install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(install);

内心独白:然而,当我第一次找到这些代码的时候,先是很开心,然后很苦恼,最后近乎崩溃,然后就是回到最开始一样的开心,因为我终于还是实现了。

上面的代码是我们需要写到android studio工程的java类里面的一个方法的内容。我们不妨给它加上一个“盖子”使他看起来更完整:

public void installApk(String path){
 Intent install = new Intent(Intent.ACTION_VIEW);
            install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
            install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(install);
}

这个时候当你复制代码到你的安卓工程里的时候,你会发现有很多地方需要添加引用,那么你可以alt+enter进行引用:像这样
然后你会发现 找不到 apkFile ??纳尼?!这。。没关系,我们尝试着学一学安卓呗,这时候我们一定下定决心要搞明白它了。

  1. 那么就让我去搜搜这个setDataAndType()方法是干嘛的:
    如果你百度了,你会发现他是设置数据和类型的一个方法。里面第一个参数是一个uri,那么这个fromFile()方法又是干嘛的呢?
  2. 搜一下发现,他是从一个java的file类的对象获取一个uri对象用的,而这个file我要怎么获得呢?
  3. 搜一下发现,他是用来描述一个文件的,可以使用new file(string path)的方法创建一个file对象。
  4. 这样我们就明白了,原来我们一直想用的path在这里用到了,原作者的apkfile也就是这个意思,那么我们的代码就变成了这样:
    在这里插入图片描述
    这个时候你会发现,还有一个报红无法直接引用处理,那就是startActivity(install)那么这个是什么呢?字面意思开启一个活动。于是你去搜activity是什么。你发现activity是安卓架构中的基本逻辑实现单元,一个activity就像一个活动窗口一样,就像一个进程。他可以被启动,暂停,关闭和销毁等。。
    那么搜一下startActivity方法,你会发现她需要一个context去调用,而activity继承自context,是不是有点像 gameObject继承自Monobehavior?哈哈,没错,可以联想记忆。

那么,我们如果开启这个activity呢?
记得前面我们做安卓unity交互的代码里有获取activity的方法吗?既然startActivity需要context去调用,而activity又继承自context,那么我们可不可以获取当前的activity去调用这个方法,开始安装apk的这个activity呢?答案是可以的,最终我们的代码成了这样:
在这里插入图片描述
到此,这个“简单的”四行代码我们就可以使用了。那么进入unity中调用这个方法,传入我们更新下来的apk的地址,就可以实现逻辑更新了。

完整的安卓代码是这样的:

package com.eric.unity;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.widget.Toast;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by Jing on 2018-1-18.
 */
public class Unity2Android {

    /**
     * unity项目启动时的的上下文
     */
    private Activity _unityActivity;
    /**
     * 获取unity项目的上下文
     * @return
     */
    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) {

            } catch (IllegalAccessException e) {

            } catch (NoSuchFieldException e) {

            }
        }
        return _unityActivity;
    }

    /**
     * 调用Unity的方法
     * @param gameObjectName    调用的GameObject的名称
     * @param functionName      方法名
     * @param args              参数
     * @return                  调用是否成功
     */
    boolean callUnity(String gameObjectName, String functionName, String args){
        try {
            Class<?> classtype = Class.forName("com.unity3d.player.UnityPlayer");
            Method method =classtype.getMethod("UnitySendMessage", String.class,String.class,String.class);
            method.invoke(classtype,gameObjectName,functionName,args);
            return true;
        } catch (ClassNotFoundException e) {

        } catch (NoSuchMethodException e) {

        } catch (IllegalAccessException e) {

        } catch (InvocationTargetException e) {

        }
        return false;
    }

    /**
     * Toast显示unity发送过来的内容
     * @param content           消息的内容
     * @return                  调用是否成功
     */
    public boolean showToast(String content){
        Toast.makeText(getActivity(),content,Toast.LENGTH_SHORT).show();
        //这里是主动调用Unity中的方法,该方法之后unity部分会讲到
        callUnity("Main Camera","FromAndroid", "hello unity i'm Eric android");
        return true;
    }

    public void installApk(String path){
        Intent install = new Intent(Intent.ACTION_VIEW);
        install.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
        install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        getActivity().startActivity(install);
    }
}

这时候如果你想找Unity端代码该怎么调用,那么你要回去看一下前面引用的unity调用安卓的链接,同理调用安卓的这个方法就可以了,调用时传入apk文件的路径。执行,就可以更新了。不会的问我,但我希望你平静认真的思考过了~

注意:第一行的package 也就是java中的包名,你要用你自己的程序包的包名喔~
复制粘贴之前看一下自己的是什么。

注意2:这种方法只能更新android7.0版本之前的apk,而且不需要更改manifest文件以及不需要添加res/xml目录,不需要path.xml。

注意3:如果你需要更新的时android7.0以后的版本,那么同样的方法,不过你需要修改一下manifest和添加path.xml,具体方法就不像这样详细的讲了,自己可以看一下爱在这里:

https://blog.csdn.net/male09/article/details/78621183
up:@红叶岭谷
感谢!

白羽Eric-2019.11.5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值