Pārlūkot izejas kodu

[feat]键盘插件,设置页,如果app只是在后台,调Flutter跳转方法前,需要将app从后台拉起到前台后,再进行flutter页面跳转

hezihao 7 mēneši atpakaļ
vecāks
revīzija
3bcf9e71d7

+ 6 - 3
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/KeyboardAndroidPlugin.kt

@@ -8,6 +8,8 @@ import com.atmob.keyboard_android.component.base.interceptor.RouteInterceptorMan
 import com.atmob.keyboard_android.component.listener.ComponentUpdateLoggingListener
 import com.atmob.keyboard_android.constant.PluginConfig
 import com.atmob.keyboard_android.floating.FloatingButtonService
+import com.atmob.keyboard_android.util.AppMonitor
+import com.atmob.keyboard_android.util.ContextUtil
 import com.atmob.keyboard_android.util.FloatingWindowUtil
 import com.atmob.keyboard_android.util.InputMethodUtil
 import com.atmob.keyboard_android.util.LogUtil
@@ -30,15 +32,16 @@ class KeyboardAndroidPlugin : FlutterPlugin, MethodCallHandler {
     companion object {
         init {
             // 伴生对象的初始化,相当于Java的静态代码块,只初始化一次
-            initActivityProvider()
+            initActivityUtil()
             initComponentApi()
         }
 
         /**
-         * 初始化Activity提供者
+         * 初始化Activity工具类
          */
-        private fun initActivityProvider() {
+        private fun initActivityUtil() {
             ActivityProvider.initialize()
+            AppMonitor.get().initialize(ContextUtil.getContext())
         }
 
         /**

+ 23 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/ActivityUtil.kt

@@ -0,0 +1,23 @@
+package com.atmob.keyboard_android.util
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.Context.ACTIVITY_SERVICE
+
+/**
+ * Activity工具类
+ */
+class ActivityUtil private constructor() {
+    companion object {
+        /**
+         * 将Activity从后台,移动到前台
+         */
+        fun moveToFront(context: Context) {
+            val activityManager = context.getSystemService(ACTIVITY_SERVICE) as ActivityManager
+            val taskList = activityManager.getAppTasks() ?: listOf<ActivityManager.AppTask>()
+            if (taskList.isNotEmpty()) {
+                taskList.first().moveToFront()
+            }
+        }
+    }
+}

+ 274 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/AppMonitor.java

@@ -0,0 +1,274 @@
+package com.atmob.keyboard_android.util;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * App前、后台监控
+ */
+public class AppMonitor {
+    /**
+     * 注册了的监听器
+     */
+    private List<Callback> mListener;
+    /**
+     * 注册了的过滤器
+     */
+    private List<Filter> mFilters;
+    /**
+     * 是否初始化了
+     */
+    private boolean isInited;
+    /**
+     * 活跃Activity的数量
+     */
+    private int mActiveActivityCount = 0;
+    /**
+     * 存活的Activity数量
+     */
+    private int mAliveActivityCount = 0;
+    /**
+     * 是否活跃,该标志位是为了过滤重复调用的问题
+     */
+    private boolean isActive;
+
+    private AppMonitor() {
+    }
+
+    public static AppMonitor get() {
+        return SingleHolder.INSTANCE;
+    }
+
+    private static final class SingleHolder {
+        private static final AppMonitor INSTANCE = new AppMonitor();
+    }
+
+    public void initialize(Context context) {
+        if (isInited) {
+            return;
+        }
+        mListener = new CopyOnWriteArrayList<>();
+        mFilters = new CopyOnWriteArrayList<>();
+        registerLifecycle(context);
+        isInited = true;
+    }
+
+    /**
+     * 注册生命周期
+     */
+    private void registerLifecycle(Context context) {
+        Application application = (Application) context.getApplicationContext();
+        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
+            @Override
+            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+                boolean isIgnore = false;
+                for (Filter filter : mFilters) {
+                    if (filter.isIgnore(activity)) {
+                        isIgnore = true;
+                    }
+                }
+                if (isIgnore) {
+                    return;
+                }
+                mAliveActivityCount++;
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                boolean isIgnore = false;
+                for (Filter filter : mFilters) {
+                    if (filter.isIgnore(activity)) {
+                        isIgnore = true;
+                    }
+                }
+                if (isIgnore) {
+                    return;
+                }
+                mActiveActivityCount++;
+                notifyChange();
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                boolean isIgnore = false;
+                for (Filter filter : mFilters) {
+                    if (filter.isIgnore(activity)) {
+                        isIgnore = true;
+                    }
+                }
+                if (isIgnore) {
+                    return;
+                }
+                mActiveActivityCount--;
+                notifyChange();
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                boolean isIgnore = false;
+                for (Filter filter : mFilters) {
+                    if (filter.isIgnore(activity)) {
+                        isIgnore = true;
+                    }
+                }
+                if (isIgnore) {
+                    return;
+                }
+                mAliveActivityCount--;
+                notifyAppAliveChange();
+            }
+        });
+    }
+
+    /**
+     * 判断App是否活着
+     */
+    public boolean isAppAlive() {
+        return mAliveActivityCount > 0;
+    }
+
+    /**
+     * 判断App是否在前台
+     */
+    public boolean isAppForeground() {
+        return mActiveActivityCount > 0;
+    }
+
+    /**
+     * 判断App是否在后台
+     */
+    public boolean isAppBackground() {
+        return mActiveActivityCount <= 0;
+    }
+
+    /**
+     * 通知监听者
+     */
+    private void notifyChange() {
+        if (mActiveActivityCount > 0) {
+            if (!isActive) {
+                for (Callback callback : mListener) {
+                    callback.onAppForeground();
+                }
+                isActive = true;
+            }
+        } else {
+            if (isActive) {
+                for (Callback callback : mListener) {
+                    callback.onAppBackground();
+                }
+                isActive = false;
+            }
+        }
+    }
+
+    /**
+     * 通知监听者界面销毁
+     */
+    private void notifyAppAliveChange() {
+        if (mAliveActivityCount == 0) {
+            for (Callback callback : mListener) {
+                callback.onAppUIDestroyed();
+            }
+            isActive = false;
+        }
+    }
+
+    public interface Callback {
+        /**
+         * 当App切换到前台时回调
+         */
+        void onAppForeground();
+
+        /**
+         * App切换到后台时回调
+         */
+        void onAppBackground();
+
+        /**
+         * App所有界面都销毁了
+         */
+        void onAppUIDestroyed();
+    }
+
+    public static class CallbackAdapter implements Callback {
+
+        @Override
+        public void onAppForeground() {
+        }
+
+        @Override
+        public void onAppBackground() {
+        }
+
+        @Override
+        public void onAppUIDestroyed() {
+        }
+    }
+
+    /**
+     * 过滤器,用于让调用方决定,某种情况时,是否忽略某个Activity生命周期计数
+     */
+    public interface Filter {
+        /**
+         * 是否忽略
+         *
+         * @return 忽略返回true,不忽略返回false
+         */
+        boolean isIgnore(Activity activity);
+    }
+
+    /**
+     * 注册过滤器
+     */
+    public void registerFilter(Filter filter) {
+        if (mFilters.contains(filter)) {
+            return;
+        }
+        mFilters.add(filter);
+    }
+
+    /**
+     * 取消注册过滤器
+     */
+    public void unRegisterFilter(Filter filter) {
+        mFilters.remove(filter);
+    }
+
+    /**
+     * 注册回调
+     */
+    public void register(Callback callback) {
+        if (mListener.contains(callback)) {
+            return;
+        }
+        mListener.add(callback);
+    }
+
+    /**
+     * 注销回调
+     */
+    public void unRegister(Callback callback) {
+        if (!mListener.contains(callback)) {
+            return;
+        }
+        mListener.remove(callback);
+    }
+}

+ 6 - 0
plugins/keyboard_android/android/src/main/kotlin/com/atmob/keyboard_android/util/FlutterPageLaunchUtil.kt

@@ -25,6 +25,7 @@ class FlutterPageLaunchUtil private constructor() {
             args: Map<String, Serializable?> = mapOf<String, Serializable>(),
             offAll: Boolean = false
         ) {
+            val context = ContextUtil.getContext()
             val flutterEngine = FlutterEngineHolder.getFlutterEngine()
 
             val params = mutableMapOf<String, Serializable?>()
@@ -38,6 +39,11 @@ class FlutterPageLaunchUtil private constructor() {
             // 如果Activity存在,直接通过MethodChannel跳转Flutter页面
             val currentActivity = ActivityProvider.get().currentActivity
             if (currentActivity != null && flutterEngine != null) {
+                // 如果App在后台,则将App移动到前台
+                if (AppMonitor.get().isAppBackground) {
+                    ActivityUtil.moveToFront(context)
+                }
+                // 再通知Flutter进行页面跳转
                 JumpHostAppPageUtil.jumpAppPage(params, flutterEngine)
             } else {
                 // 如果没有Activity,则通过原生Activity跳转