当前位置: 首页 > news >正文

Unity与Android交互通信系列(6)

  本节主要讲述广播订阅。

  使用AndroidJavaProxy代理接口,我们可以很方便的实现对Android端事件的订阅,灵活的进行Android端与Unity端的代码交互。通过AndroidJavaProxy代理,我们也可以在安卓端使用 BroadcastReceiver 接收广播,然后利用自定义的方法传递给C#端,但这种方式不太通用,我们希望能直接在C#端注册Android广播,下面演示一个通用的广播接收器。

  其原理依然是利用AndroidJavaProxy接口进行桥接,但通过Unity端注入action(Android端广播动作名称)参数,即由C#端控制需要注册的广播,Android端接收到广播之后,进行相应的数据处理(方便将这些数据传递到C#端),然后调用接口方法,触发C#端广播处理方法。首先我们看一下调用逻辑,代码如下:

//代码6-1
//C#端代码
using System.Collections.Generic;
using UnityEngine;
public class BroadcastExample : MonoBehaviour, UnityBroadcastHelper.IBroadcastListener
{UnityBroadcastHelper helper;void Start(){helper = UnityBroadcastHelper.Register( new string[] { "some_action_name" }, this);}public void OnReceive(string action, Dictionary<string, string> dictionary){//广播处理逻辑}void OnDisable(){helper.Stop();}
}

  通过代码13-17可以看到广播注册界面非常简洁,脚本实现了UnityBroadcastHelper.IBroadcastListener 接口,在Start()方法中初始化一个UnityBroadcastHelper 对象,然后通过OnReceive()方法等待Android端回调并进行相应处理即可,使用完后,通过OnDisable()方法停止广播监听。

  C#端UnityBroadcastHelper类代码如下:

//代码6-2
//C#端代码
using System.Collections.Generic;
using UnityEngine;
public class UnityBroadcastHelper
{//Java端对象private readonly AndroidJavaObject javaObject;//构建函数,生成唯一Java端对象实例private UnityBroadcastHelper(string[] actions, IBroadcastListener listener){ListenerAdapter adapter = new ListenerAdapter(listener, this);javaObject = new AndroidJavaObject("com.example.davidwang.UnityBroadcastHelper", actions, adapter);}//注册广播public static UnityBroadcastHelper Register(string[] actions, IBroadcastListener listener){return new UnityBroadcastHelper(actions, listener);}//取消广播订阅public void Stop(){javaObject.Call("stop");}//广播订阅者接口public interface IBroadcastListener{void OnReceive(string action, Dictionary<string, string> dictionary);}//AndroidJavaProxy实现桥接,处理数据并触发订阅方法private class ListenerAdapter : AndroidJavaProxy{readonly IBroadcastListener listener;readonly UnityBroadcastHelper helper;public ListenerAdapter(IBroadcastListener listener, UnityBroadcastHelper helper) : base("com.example.davidwang.UnityBroadcastHelper$BroadcastListener"){this.listener = listener;this.helper = helper;}void onReceive(string action){AndroidJavaObject javaObject = helper.javaObject;if (!javaObject.Call<bool>("hasKeyValue")){return;}string[] keys = javaObject.Call<string[]>("getKeys");string[] values = javaObject.Call<string[]>("getValues");javaObject.Call("pop");Dictionary<string, string> dictionary = new Dictionary<string, string>();int n = keys.Length;for (int i = 0; i < n; i++){dictionary[keys[i]] = values[i];}listener.OnReceive(action, dictionary);}}
}

  UnityBroadcastHelper类是接口的辅助类,其内部定义了IBroadcastListener接口及桥接类ListenerAdapter,并定义了注册与取消注册方法,从而简化调用端的使用。

  Java端代码如下:

//代码6-3
//Java端代码
package com.example.davidwang;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import java.util.LinkedList;
import java.util.Queue;
//引入UnityPlayer类
import com.unity3d.player.UnityPlayer;public class UnityBroadcastHelper {private static final String TAG = "UnityBroadcastHelper";//接口定义public interface BroadcastListener {void onReceive(String action);}private final BroadcastListener listener;private Queue<String[]> keysQueue = new LinkedList<>();private Queue<String[]> valuesQueue = new LinkedList<>();//构造函数,注入Unity端广播订阅者并注册广播public UnityBroadcastHelper(String[] actions, BroadcastListener listener) {this.listener = listener;IntentFilter intentFilter = new IntentFilter();for (String action : actions) {intentFilter.addAction(action);}Context context = UnityPlayer.currentActivity;if (context == null) {return;}context.registerReceiver(broadcastReceiver, intentFilter);}public boolean hasKeyValue() {return !keysQueue.isEmpty();}//返回健public String[] getKeys() {return keysQueue.peek();}//返回值public String[] getValues() {return valuesQueue.peek();}public void pop() {keysQueue.poll();valuesQueue.poll();}//取消广播注册public void stop() {Context context = UnityPlayer.currentActivity;if (context == null) {return;}context.unregisterReceiver(broadcastReceiver);}//广播处理并回调Unity中OnReceive()方法private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();MyLog.d(TAG, "UnityBroadcastHelper: action: " + action);Bundle bundle = intent.getExtras();if (bundle == null) {bundle = new Bundle();}int n = bundle.size();String[] keys = new String[n];String[] values = new String[n];int i = 0;for (String key : bundle.keySet()) {keys[i] = key;Object value = bundle.get(key);values[i] = value != null ? value.toString() : null;i++;}keysQueue.offer(keys);valuesQueue.offer(values);listener.onReceive(action);}};
}

  UnityBroadcastHelper类中的BroadcastListener接口即为需要桥接的接口,在该类的构造函数中传入了C#端定义的action及桥接实例对象并进行了广播注册操作,在stop()方法中取消了广播注册,UnityBroadcastHelper通过持有BroadcastReceiver,将广播注册到Context上下文中。为在两端进行数据传递,将Extra的Bundle数据映射为C#中的Dictionary,传递给 OnReceive()方法,方便C#代码使用。为演示简单,这里将所有类型的数据都映射成string类型,实际使用时可根据需要进行处理,如通过AndroidJavaObject进行复杂类型数据传递。

  通过使用该通用类,不仅可以注册自定义广播,也可以注册系统广播(可能需要权限申请),还可以一次性注册多个广播,界面简洁,使用简单。


提示

         本示例也需要引入UnityPlayer类,该类位于Unity提供的Classes.jar包,引入Jar包流程和处理与上节一样。

相关文章:

  • 自动化数据驱动?最全接口自动化测试yaml数据驱动实战
  • 搜索与图论:染色法判别二分图
  • LeetCode 58. 最后一个单词的长度
  • Debian/Ubuntu linux安装软件
  • 算法体系-22 第二十二节:暴力递归到动态规划(四)
  • Python对象复制竟然有这么多种方式,赶紧学起来!
  • 示例:WPF中绑定枚举到ComboBox的方式
  • 多标签识别:JoyTag模型的图像标注革命【开源】
  • rabbitmq单机安装及性能测试
  • NAND闪存市场彻底复苏
  • hive split 特殊用法
  • 如何在WordPress中上传多种安装包文件
  • 第一章 基本指令
  • Qt 信号与槽机制概述
  • 早期发现,健康生活!第三届ZAODX世界肿瘤早筛大会圆满落幕!
  • 【mysql】环境安装、服务启动、密码设置
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • css属性的继承、初识值、计算值、当前值、应用值
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • Js基础知识(四) - js运行原理与机制
  • Objective-C 中关联引用的概念
  • Selenium实战教程系列(二)---元素定位
  • spring-boot List转Page
  • Spring-boot 启动时碰到的错误
  • SpringBoot几种定时任务的实现方式
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 翻译--Thinking in React
  • 技术:超级实用的电脑小技巧
  • 三栏布局总结
  • 深入 Nginx 之配置篇
  • 使用 Docker 部署 Spring Boot项目
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 世界上最简单的无等待算法(getAndIncrement)
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 微服务入门【系列视频课程】
  • 我的业余项目总结
  • 长三角G60科创走廊智能驾驶产业联盟揭牌成立,近80家企业助力智能驾驶行业发展 ...
  • ​Linux·i2c驱动架构​
  • # 消息中间件 RocketMQ 高级功能和源码分析(七)
  • #控制台大学课堂点名问题_课堂随机点名
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)Jupyter Notebook 下载及安装
  • (4)STL算法之比较
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (python)数据结构---字典
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (算法)N皇后问题
  • (一) springboot详细介绍
  • (转)iOS字体
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在