zoukankan      html  css  js  c++  java
  • 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的方法已经很清晰了吧。
    --------------------- 

  • 相关阅读:
    Android Time类 奇葩的设定
    zjut1698Coins
    zjut1689联盟
    zju1024Calendar Game
    hdu2863Top Shooter
    hdu3974Assign the task
    hdu1150Machine Schedule
    线段树无止尽版
    zjut1684AirCraft
    hdu3926Hand in Hand
  • 原文地址:https://www.cnblogs.com/ly570/p/10992446.html
Copyright © 2011-2022 走看看