接上文 Flutter PIP 插件 ---- Android
項目地址 PIP, pub.dev也已經同步發布 pip 0.0.3,你的加星和點贊,將是我繼續改進最大的動力
開發文檔 Add videos using picture-in-picture (PiP)介紹PIP功能從 Android 8.0 (API level 26) 引入,但是autoEnter功能從 Android 12 才開始支持,那么不支持的版本呢就需要通過監聽 onUserLeaveHint 主動調用 enterPictureInPictureMode 才能進入 PIP Mode,在之前的版本中因為 FlutterActivity 沒有轉發 onUserLeaveHint,導致我們只能在 dart 中通過 flutter 的 didChangeAppLifecycleState 事件,在應用進入后臺是主動調用的方式進入PIP Mode,但實際測下來,似乎無法區分通知欄下滑的通知,這導致即使應用在前臺,當用戶下滑通知欄的時候依然會自動進入PIP Mode, 這顯然不是我們想要的,優化后的效果如下:
修改PIP插件
-
新增PipActivity
package org.opentraa.pip;import android.app.PictureInPictureUiState; import android.content.res.Configuration; import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import io.flutter.embedding.android.FlutterActivity;@RequiresApi(Build.VERSION_CODES.O) public class PipActivity extends FlutterActivity {public interface PipActivityListener {void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,Configuration newConfig);void onPictureInPictureUiStateChanged(PictureInPictureUiState state);boolean onPictureInPictureRequested();void onUserLeaveHint();}private PipActivityListener mListener;public void setPipActivityListener(PipActivityListener listener) {mListener = listener;}// only available in API level 26 and above@RequiresApi(26)@Overridepublic void onPictureInPictureModeChanged(boolean isInPictureInPictureMode,Configuration newConfig) {super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);if (mListener != null) {mListener.onPictureInPictureModeChanged(isInPictureInPictureMode,newConfig);}}// only available in API level 30 and above@RequiresApi(30)@Overridepublic boolean onPictureInPictureRequested() {if (mListener != null) {return mListener.onPictureInPictureRequested();}return super.onPictureInPictureRequested();}// only available in API level 31 and above@RequiresApi(31)@Overridepublic voidonPictureInPictureUiStateChanged(@NonNull PictureInPictureUiState state) {super.onPictureInPictureUiStateChanged(state);if (mListener != null) {mListener.onPictureInPictureUiStateChanged(state);}}@Overridepublic void onUserLeaveHint() {super.onUserLeaveHint();if (mListener != null) {mListener.onUserLeaveHint();}} }
主要思路就是如果PIP 插件的用戶想要在 Android 12 以下支持應用進入后臺自動進入 PIP Mode 的話,可以將自己 MainActivity 的父類修改為 PipActivity ,這樣在 PIP 插件被注冊時,可以通過判斷傳入的 Activity 是否是 PipActivity 來決定是否啟用相關的功能。
-
綁定 Activity 到 PipController
PipPlugin 在 onAttachedToActivity 和 onReattachedToActivityForConfigChanges 的時候去初始化 PipControllerprivate void initPipController(@NonNull ActivityPluginBinding binding) {if (pipController == null) {pipController = new PipController(binding.getActivity(), new PipController.PipStateChangedListener() {@Overridepublic void onPipStateChangedListener(PipController.PipState state) {// put state into a json objectchannel.invokeMethod("stateChanged",new HashMap<String, Object>() {{ put("state", state.getValue()); }});}});} else {pipController.attachToActivity(binding.getActivity());} }@Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {initPipController(binding); }@Override public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {initPipController(binding); }
-
在 PipController 構造函數和 attachToActivity 方法中去綜合當前的系統版本和綁定的 Activity 進行檢查是否支持 autoEnter
public PipController(@NonNull Activity activity,@Nullable PipStateChangedListener listener) {setActivity(activity);// ... Other code ... }private boolean checkAutoEnterSupport() {// Android 12 and above support to set auto enter enabled directlyif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {return true;}// For android 11 and below, we need to check if the activity is kind of// PipActivity since we can enter pip mode when the onUserLeaveHint is// called to enter pip mode as a workaroundActivity activity = mActivity.get();return activity instanceof PipActivity; }private void setActivity(Activity activity) {mActivity = new WeakReference<>(activity);if (activity instanceof PipActivity) {((PipActivity)activity).setPipActivityListener(this);}mIsSupported = checkPipSupport();mIsAutoEnterSupported = checkAutoEnterSupport(); }public void attachToActivity(@NonNull Activity activity) {setActivity(activity); }
修改Example項目中的MainActivity
- 孤伶伶的MainActivity
package org.opentraa.pip_example;import io.flutter.embedding.android.FlutterActivity; import org.opentraa.pip.PipActivity;public class MainActivity extends PipActivity { }
如上,至此我們已經支持了全部版本的 PIP Mode autoEnter 功能。