Communication middleware Unity and 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 is
39
40
41 is
42 is
that class very simple, the Activity, Fragment, Fragment of abstract methods v4 packet just under unified, convenient package BaseActivity, BaseFragment, BaseFragmentV4. For example contentViewLayoutId method is to allow developers to directly back id layout, but do not have to write code to load the layout.

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 is
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
1 16
117
1 18
119
120
121
122
123
124
125
126
127
128
129
130.
131 is
132
133
134
135
This three principal is to simplify the code developer to load layout-related, as well as simplifying the number of lifecycle callback methods, so developers only care about the concerns of lifecycle callbacks.

2.1.3 the base class for further encapsulated module Unity --UnityPlayerActivity end view, 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
Do not look at this class has 200 lines, in fact, most of the code is overloaded, in order to meet the needs of Unity end, the real way to pay attention to it so three or four, only generateIOnUnity3DCallDelegate (@NonNull UnityPlayer unityPlayer , @ Nullable bundle bundle) inherited this method requires implementers to focus on the role of this method is to generate a real end to load and display Unity view of the module, you are not off view Ye Hao, Fragment, but whatever you realized IOnUnity3DCall IUnityPlayerContainer interfaces and interfaces, you can load and view end Unity display.

By default, the class is inherited UnityPlayerActivity to load and display module Unity end view, unless you override generateIOnUnity3DCallDelegate (@NonNull UnityPlayer unityPlayer, @ Nullable Bundle bundle) method that returns the appropriate agent, this can be from initUnityPlayer (@NonNull Bundle the bundle) method intuitive see inside.

If you want to go further, to achieve the agent module IOnUnity3DCall interface and the interface IUnityPlayerContainer also want to show the other modules Unity short View, then realized the agent module IOnUnity3DCall IUnityPlayerContainer interfaces and interfaces can be achieved in IGetUnity3DCall interface rewrite generateIOnUnity3DCallDelegate (@NonNull unityPlayer unityPlayer, @ Nullable Bundle bundle) method returns the appropriate agent. Of course, in most cases we may not need to do it.

Based on the above principle, let Fragment method as a display module Unity short View of almost certain of:

Fragment under v4 packet

/**
* 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 gatContext the Context () {
return getActivity ();
}
}
. 1
2
. 3
. 4
. 5
. 6
. 7
. 8
. 9
10
. 11
12 is
13 is
14
15
16
. 17
18 is
. 19
20 is
21 is
22 is
23 is
24
25
26 is
27
28
29
achieved both exactly the same, just to make developers less a package for a Fragment. I think that when you see here, the method of how to make a heart or ViewGroup Dialog displayed View Unity side has been very clear it.
--------------------- 

Guess you like

Origin www.cnblogs.com/ly570/p/10992446.html