Unity与Android通信的中间件
2.1.1 Fragment和Activity都需要实现的接口——IBaseView
/**
* Description:Basic interface of all {@link Activity}
* or
* {@link Fragment}
* or
* {@link android.app.Fragment}
* <p>
* Creator:yankebin
* CreatedAt:2018/12/18
*/
public interface IBaseView {
/**
* Return the layout resource
*
* @return Layout Resource
*/
@LayoutRes
int contentViewLayoutId();
/**
* Call after {@link Activity#onCreate(Bundle)}
* or
* {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}
* or
* {@link android.app.Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}
*
* @param params
* @param contentView
*/
void onViewCreated(@NonNull Bundle params, @NonNull View contentView);
/**
* Call after
* {@link Activity#onDestroy()} (Bundle)}
* or
* {@link Fragment#onDestroyView()}
* or
* {@link android.app.Fragment#onDestroyView()}
*/
void onVieDestroyed();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
这个类很简单的,只是统一下Activity、Fragment、v4包的Fragment的一些抽象方法,方便封装BaseActivity、BaseFragment、BaseFragmentV4。比如contentViewLayoutId方法,就是让开发者可以直接返回布局的id,而不用自己去写加载布局的代码。
2.1.2 显示Unity端视图的模块的基类——BaseActivity、BaseFragment、BaseFragmentV4
/**
* Description:Activity基类
* Creator:yankebin
* CreatedAt:2018/12/18
*/
public abstract class BaseActivity extends AppCompatActivity implements IBaseView {
protected View mainContentView;
protected Unbinder unbinder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainContentView = getLayoutInflater().inflate(contentViewLayoutId(),
(ViewGroup) getWindow().getDecorView(), false);
setContentView(mainContentView);
unbinder = ButterKnife.bind(this, mainContentView);
Bundle bundle = getIntent().getExtras();
if (null == bundle) {
bundle = new Bundle();
}
if (null != savedInstanceState) {
bundle.putAll(savedInstanceState);
}
onViewCreated(bundle, mainContentView);
}
@Override
protected void onDestroy() {
onVieDestroyed();
if (null != unbinder) {
unbinder.unbind();
}
mainContentView = null;
super.onDestroy();
}
}
/**
* Description:app包下Fragment作为基类封装
* Creator:yankebin
* CreatedAt:2018/12/18
*/
@Deprecated
public abstract class BaseFragment extends Fragment implements IBaseView {
protected Unbinder unbinder;
protected View mainContentView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (null == mainContentView) {
mainContentView = inflater.inflate(contentViewLayoutId(), container, false);
unbinder = ButterKnife.bind(this, mainContentView);
Bundle bundle = getArguments();
if (null == bundle) {
bundle = new Bundle();
}
if (null != savedInstanceState) {
bundle.putAll(savedInstanceState);
}
onViewCreated(bundle, mainContentView);
} else {
unbinder = ButterKnife.bind(this, mainContentView);
}
return mainContentView;
}
@Override
public void onDetach() {
mainContentView = null;
super.onDetach();
}
@Override
public void onDestroyView() {
onVieDestroyed();
if (null != unbinder) {
unbinder.unbind();
}
if (mainContentView != null && mainContentView.getParent() != null) {
((ViewGroup) mainContentView.getParent()).removeView(mainContentView);
}
super.onDestroyView();
}
}
/**
* Description:V4包下Fragment作为基类封装
* Creator:yankebin
* CreatedAt:2018/12/18
*/
public abstract class BaseFragmentV4 extends Fragment implements IBaseView {
protected Unbinder unbinder;
protected View mainContentView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
if (null == mainContentView) {
mainContentView = inflater.inflate(contentViewLayoutId(), container, false);
unbinder = ButterKnife.bind(this, mainContentView);
Bundle bundle = getArguments();
if (null == bundle) {
bundle = new Bundle();
}
if (null != savedInstanceState) {
bundle.putAll(savedInstanceState);
}
onViewCreated(bundle, mainContentView);
} else {
unbinder = ButterKnife.bind(this, mainContentView);
}
return mainContentView;
}
@Override
public void onDetach() {
mainContentView = null;
super.onDetach();
}
@Override
public void onDestroyView() {
onVieDestroyed();
if (null != unbinder) {
unbinder.unbind();
}
if (mainContentView != null && mainContentView.getParent() != null) {
((ViewGroup) mainContentView.getParent()).removeView(mainContentView);
}
super.onDestroyView();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
这三个类主要是简化了开发者加载布局相关的代码,以及简化生命周期回调的方法数量,让开发者只关心该关注的生命周期回调。
2.1.3 显示Unity端视图的模块的基类进一步封装——UnityPlayerActivity、UnityPlayerFragment、UnityPlayerFragmentV4
UnityPlayerActivity:
/**
* Desription:Base Unity3D Player Activity.
* <BR/>
* If you want to implement Fragment to load the Unity scene, then the Fragment needs to refer to {@link UnityPlayerFragment} and {@link UnityPlayerFragmentV4}
* To implement, then overload the {@link #generateIOnUnity3DCallDelegate(UnityPlayer, Bundle)} method to return the conforming Fragment.
* <BR/>
* Creator:yankebin
* <BR/>
* CreatedAt:2018/12/1
*/
public abstract class UnityPlayerActivity extends BaseActivity implements IGetUnity3DCall, IOnUnity3DCall, IUnityPlayerContainer {
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
protected IOnUnity3DCall mOnUnity3DCallDelegate;
@Override
@CallSuper
public void onViewCreated(@NonNull Bundle params, @NonNull View contentView) {
initUnityPlayer(params);
}
/**
* Initialize Unity3D related
*
* @param bundle {@link Bundle}
*/
protected void initUnityPlayer(@NonNull Bundle bundle) {
mUnityPlayer = new UnityPlayer(this);
mOnUnity3DCallDelegate = generateIOnUnity3DCallDelegate(mUnityPlayer, bundle);
if (null != mOnUnity3DCallDelegate) {
if (mOnUnity3DCallDelegate instanceof Fragment) {
getSupportFragmentManager().beginTransaction().replace(unityPlayerContainerId(),
(Fragment) mOnUnity3DCallDelegate, ((Fragment) mOnUnity3DCallDelegate)
.getClass().getName()).commit();
} else if (mOnUnity3DCallDelegate instanceof android.app.Fragment) {
getFragmentManager().beginTransaction().replace(unityPlayerContainerId(),
(android.app.Fragment) mOnUnity3DCallDelegate, ((android.app.Fragment) mOnUnity3DCallDelegate)
.getClass().getName()).commit();
} else if (mOnUnity3DCallDelegate instanceof View) {
final ViewGroup unityContainer = findViewById(unityPlayerContainerId());
unityContainer.addView((View) mOnUnity3DCallDelegate);
} else {
throw new IllegalArgumentException("Not support type : " + mOnUnity3DCallDelegate.toString());
}
} else {
mOnUnity3DCallDelegate = this;
final ViewGroup unityContainer = findViewById(unityPlayerContainerId());
unityContainer.addView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
}
@Override
protected void onNewIntent(Intent intent) {
// To support deep linking, we need to make sure that the client can get access to
// the last sent intent. The clients access this through a JNI api that allows them
// to get the intent set on launch. To update that after launch we have to manually
// replace the intent with the one caught here.
setIntent(intent);
}
// Quit Unity
@Override
protected void onDestroy() {
if (null != mUnityPlayer) {
mUnityPlayer.quit();
}
super.onDestroy();
}
// Pause Unity
@Override
protected void onPause() {
super.onPause();
if (null != mUnityPlayer) {
mUnityPlayer.pause();
}
}
// Resume Unity
@Override
protected void onResume() {
super.onResume();
if (null != mUnityPlayer) {
mUnityPlayer.resume();
}
}
@Override
protected void onStart() {
super.onStart();
if (null != mUnityPlayer) {
mUnityPlayer.start();
}
}
@Override
protected void onStop() {
super.onStop();
if (null != mUnityPlayer) {
mUnityPlayer.stop();
}
}
// Low Memory Unity
@Override
public void onLowMemory() {
super.onLowMemory();
if (null != mUnityPlayer) {
mUnityPlayer.lowMemory();
}
}
// Trim Memory Unity
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == TRIM_MEMORY_RUNNING_CRITICAL) {
if (null != mUnityPlayer) {
mUnityPlayer.lowMemory();
}
}
}
// This ensures the layout will be correct.
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (null != mUnityPlayer) {
mUnityPlayer.configurationChanged(newConfig);
}
}
// Notify Unity of the focus change.
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (null != mUnityPlayer) {
mUnityPlayer.windowFocusChanged(hasFocus);
}
}
// For some reason the multiple keyevent type is not supported by the ndk.
// Force event injection by overriding dispatchKeyEvent().
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
if (null != mUnityPlayer) {
return mUnityPlayer.injectEvent(event);
}
}
return super.dispatchKeyEvent(event);
}
// Pass any events not handled by (unfocused) views straight to UnityPlayer
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyUp(keyCode, event);
}
if (null != mUnityPlayer) {
return mUnityPlayer.injectEvent(event);
}
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
return super.onKeyDown(keyCode, event);
}
if (null != mUnityPlayer) {
return mUnityPlayer.injectEvent(event);
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (null != mUnityPlayer) {
return mUnityPlayer.injectEvent(event);
}
return super.onTouchEvent(event);
}
/*API12*/
public boolean onGenericMotionEvent(MotionEvent event) {
if (null != mUnityPlayer) {
return mUnityPlayer.injectEvent(event);
}
return super.onGenericMotionEvent(event);
}
@Nullable
@Override
public Context gatContext() {
return this;
}
@NonNull
@Override
public IOnUnity3DCall getOnUnity3DCall() {
//Perhaps this method is called after Unity is created after the activity is created,
// so there is no problem for the time being.
return mOnUnity3DCallDelegate;
}
@Nullable
protected IOnUnity3DCall generateIOnUnity3DCallDelegate(@NonNull UnityPlayer unityPlayer,
@Nullable Bundle bundle) {
return null;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
别看这个类有200多行,其实绝大部分代码都是重载,是为了满足Unity端的需求,真正要关注的方法就那么三四个,只有generateIOnUnity3DCallDelegate(@NonNull UnityPlayer unityPlayer,@Nullable Bundle bundle)这个方法需要继承的实现者去关注,这个方法的作用就是生成真正去加载和显示Unity端使视图的模块,不关你是View也好,Fragment也好,只要你实现了IOnUnity3DCall接口和IUnityPlayerContainer接口,你就可以加载和显示Unity端的视图。
默认情况下,继承至UnityPlayerActivity的类就是加载和显示Unity端视图的模块,除非你重写generateIOnUnity3DCallDelegate(@NonNull UnityPlayer unityPlayer,@Nullable Bundle bundle)方法,返回合适的代理,这个可以从initUnityPlayer(@NonNull Bundle bundle) 方法里面直观的看出来。
如果你还想再进一步,实现了IOnUnity3DCall接口和IUnityPlayerContainer接口的代理模块还想让其他模块来显示Unity短的View,那么实现了IOnUnity3DCall接口和IUnityPlayerContainer接口的代理模块就可以在实现IGetUnity3DCall接口,重写generateIOnUnity3DCallDelegate(@NonNull UnityPlayer unityPlayer,@Nullable Bundle bundle)方法,返回合适的代理。当然,可能大多数情况下我们也不需要这么做吧。
基于以上的原理,要让Fragment作为显示Unity短的View的模块的方法就呼之欲出了:
v4包下的Fragment
/**
* Description:The base Unity3D fragment, the Activity holding this Fragment needs to implement the {@link IGetUnity3DCall} interface and implement {@link IGetUnity3DCall#getOnUnity3DCall()}
* 方法返回此Fragment的实例
* Creator:yankebin
* CreatedAt:2018/12/1
*/
public abstract class UnityPlayerFragmentV4 extends BaseFragmentV4 implements IOnUnity3DCall, IUnityPlayerContainer {
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
public void setUnityPlayer(@NonNull UnityPlayer mUnityPlayer) {
this.mUnityPlayer = mUnityPlayer;
}
@Override
@CallSuper
public void onViewCreated(@NonNull Bundle params, @NonNull View contentView) {
if (null != mUnityPlayer) {
final ViewGroup unityContainer = contentView.findViewById(unityPlayerContainerId());
unityContainer.addView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
}
@Nullable
@Override
public Context gatContext() {
return getActivity();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
app包下的Fragment
/**
* Description:The base Unity3D fragment, the Activity holding this Fragment needs to implement the {@link IGetUnity3DCall} interface and implement {@link IGetUnity3DCall#getOnUnity3DCall()}
* Method returns an instance of this Fragment
* Creator:yankebin
* CreatedAt:2018/12/1
*/
public abstract class UnityPlayerFragment extends BaseFragment implements IOnUnity3DCall, IUnityPlayerContainer {
protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code
public void setUnityPlayer(@NonNull UnityPlayer mUnityPlayer) {
this.mUnityPlayer = mUnityPlayer;
}
@Override
@CallSuper
public void onViewCreated(@NonNull Bundle params, @NonNull View contentView) {
if (null != mUnityPlayer) {
final ViewGroup unityContainer = contentView.findViewById(unityPlayerContainerId());
unityContainer.addView(mUnityPlayer);
mUnityPlayer.requestFocus();
}
}
@Nullable
@Override
public Context gatContext() {
return getActivity();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
两者的实现完全一致,只是为了让开发者少封装一种Fragment。我想,当你们看到这里的时候,心中对如何让一个ViewGroup或者Dialog显示Unity端的View的方法已经很清晰了吧。
---------------------
Unity与Android通信的中间件的更多相关文章
- Unity之SDK接入(Unity与Android通信)
首先介绍一点关于Android与unity通信的知识: 完成通信主要靠unity中的class.jar包(在unity的安装目录下). 在unity中调用android的方法: jo.call(&qu ...
- 没有指定非静态方法,Unity与Android通信错误
报错信息: AndroidJavaException: java.lang.NoSuchMethodError: no non-static method with name='InstallApk' ...
- Unity 调用android插件
1. Unity的Bundle Identifier必须和你的android报名一致 Activity和View的区别: Activity应该是一个展示页面,View是页面上一些按钮视图等等. 如何调 ...
- 【Unity与Android】01-Unity与Android交互通信的简易实现
前言 使用Unity也有不短的时间了,安卓包也打过不少,但是对Unity与Android的交互却知之甚少. 因工作需求,需要在Android平台接一些sdk(扩展功能).我就借此机会就了解了下Unit ...
- Unity - 接入Android SDK
在网络上,关于Unity与Android如何进行交互,雨松MOMO大神已经有两篇文章简单介绍了如何操作(1)Unity3D研究院之打开Activity与调用JAVA代码传递参数(2)Unity3D研究 ...
- Unity开发Android应用程序:调用安卓应用程序功能
开发环境: Eclipse3.4 + adt12 + jdk6 + AndroidSDK2.2 Unity3.4 + windows7 测试设备: HTC Desire HD 本文要涉及到的几个重点问 ...
- [Unity][安卓]Unity和Android Studio 3.0 交互通讯(1)Android Studio 3.0 设置
[安卓]Android Studio 3.0 JDK安卓环境配置(2017.10) http://blog.csdn.net/bulademian/article/details/78387052 [ ...
- 【Unity与Android】02-在Unity导出的Android工程中接入Google Admob广告
我在上一篇文章 [Unity与Android]01-Unity与Android交互通信的简易实现) 中介绍了Unity与Android通讯的基本方法. 这一篇开始进入应用阶段,这次要介绍的是如何在An ...
- Unity调用Android相册
最近有一个项目有这个需求,让用户上传自己的交易凭证的截图,之前因为对调Android原生的东西不太熟悉,就先放了一边 因为项目已经上线,只不过是该功能未开放而已,那么现在为什么要写这篇博客呢,是因为. ...
随机推荐
- 【Developer Log】ProGuard扰码可执行JAR包
在项目上线之前需要通过ProGuard来对java的class进行混淆,以避免反编译方式,来保护自己的代码.ProGuard网上有很多资料,可以参考:http://blog.csdn.net/zhan ...
- CPU工作原理简图
- 快速傅立叶变换&HDU 1402
参考http://www.cnblogs.com/v-July-v/archive/2011/08/13/2214132.html <算导> 那么,更快速的多项式乘法就依赖于能否把一个系数 ...
- (转)linux口令相关文件(/etc/passwd和/etc/shadow)
在linux中,口令文件在/etc/passwd中,早期的这个文件直接存放加密后的password,前两位是"盐"值,是一个随机数.后面跟的是加密的password.为了安全,如今 ...
- jquery ajax CORS 跨域訪问 WebService
JS代码: var word = document.getElementById("word").value; $.ajax({ type: "POST", c ...
- DirectX11 学习笔记8 - 最简单的光照
在上一个列子的基础上加了一个地面.这个地面是光照效果生成的. 看图: 先说明: 光照 须要重写一个 lightshader 就是光照的渲染器 // Define the input layout D ...
- 创建虚拟机中的nova-scheduler 调度配置
一个Openstack 系统中通常包括多个计算节点 root@controller:/etc/nova# nova hypervisor-list +----+-------------------- ...
- kafka的topic和分区策略——log entry和消息id索引文件
Topic在逻辑上可以被认为是一个在的queue,每条消费都必须指定它的topic,可以简单理解为必须指明把这条消息放进哪个queue里. 为了使得Kafka的吞吐率可以水平扩展,物理上把topic分 ...
- B1085 [SCOI2005]骑士精神 A*搜索
其实就是一个爆搜加剪枝.直接爆搜肯定不行,而A*算法则是想假如剩下都是最优的话,我当前步数还是不足以达到这个状态,那么就直接返回,因为最优状态也无法做到显然不行. 这道题可以用A*最主要就是因为有15 ...
- Tool-Java:Spring Tool Suite
ylbtech-Tool-Java:Spring Tool Suite Spring Tool Suite 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 0. ...