diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a509303 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +.DS_Store +.dart_tool/ +example/.dart_tool/ + +.packages +.pub/ + +build/ +example/ios/Podfile.lock +example/ios/Pods/ +flutter/tools/local.json +flutter/ios_crash/raw_crash + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.vscode/settings.json +.settings/ +.project +example/android/.gradle/4.10.2/vcsMetadata-1/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 35b08d0..296916c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,31 +1,4 @@ -## [0.5.6] - 13-05-2019 - -* added null check in Android layout callback -* changed behavior on dispose -* catching exceptions if callbacks are not unsubscribed properly - -## [0.5.5] - 11-05-2019 - -* Changed README.md and formatted Dart code - -## [0.5.4] - 11-05-2019 - -* Fixed plugin registration bug - -## [0.5.3] - 09-05-2019 - -* Fixed exception call bug on dispose -* Change behavior of plugin registration - -## [0.5.2] - 12-03-2019 - -* Fixed possible bug on dispose -* On iOS the keyboard pop up message is already being sent when keyboard starts popping up - -## [0.5.1] - 06-01-2019 - -* Fixed bug when using multiple listeners on same page - -## [0.5.0] - 06-12-2018 - -* Initial release, working on Android and iOS +## [0.0.1] - 适配混合栈 +clone from https://github.com/adee42/flutter_keyboard_visibility +在已有的基础上适配了混合栈 +监听了Android ios的键盘弹出 diff --git a/README.md b/README.md index 2837343..126a08c 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,13 @@ -# keyboard_visibility +# keyboard_visibility_hybrid +clone from https://github.com/adee42/flutter_keyboard_visibility +在原有库的基础上适配了Android混合栈,给原先的库提了pr,但貌似已经没人维护了,自己发个 Notification service for soft-keyboard visibility # Usage -Add the dependency to your pubspec.yaml file in the root folder of your project. -Look for the 'dependencies:'-line and add the following line after this line: ``` -keyboard_visibility: any -``` -or -``` -keyboard_visibility: ^[CURRENT VERSION NUMBER] +keyboard_visibility_hybrid: ^0.0.1 ``` (Please note that the two spaces in the beginning of the line are important) diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/android/build.gradle b/android/build.gradle index b6a428f..6baebf4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -22,7 +22,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { minSdkVersion 16 diff --git a/android/src/main/java/com/github/adee42/keyboardvisibility/KeyboardVisibilityPlugin.java b/android/src/main/java/com/github/adee42/keyboardvisibility/KeyboardVisibilityPlugin.java index bc45dff..d90bf90 100644 --- a/android/src/main/java/com/github/adee42/keyboardvisibility/KeyboardVisibilityPlugin.java +++ b/android/src/main/java/com/github/adee42/keyboardvisibility/KeyboardVisibilityPlugin.java @@ -1,24 +1,19 @@ package com.github.adee42.keyboardvisibility; -import io.flutter.plugin.common.EventChannel; -import io.flutter.plugin.common.EventChannel.EventSink; -import io.flutter.plugin.common.EventChannel.StreamHandler; -import io.flutter.plugin.common.MethodChannel; -import io.flutter.plugin.common.MethodChannel.MethodCallHandler; -import io.flutter.plugin.common.MethodChannel.Result; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.PluginRegistry; -import io.flutter.plugin.common.PluginRegistry.Registrar; - import android.app.Activity; import android.app.Application; -import android.content.Intent; import android.graphics.Rect; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import io.flutter.embedding.android.FlutterView; +import io.flutter.plugin.common.EventChannel; +import io.flutter.plugin.common.EventChannel.EventSink; +import io.flutter.plugin.common.EventChannel.StreamHandler; +import io.flutter.plugin.common.PluginRegistry.Registrar; + public class KeyboardVisibilityPlugin implements StreamHandler, Application.ActivityLifecycleCallbacks, ViewTreeObserver.OnGlobalLayoutListener { private static final String STREAM_CHANNEL_NAME = "github.com/adee42/flutter_keyboard_visibility"; @@ -29,56 +24,89 @@ public class KeyboardVisibilityPlugin implements StreamHandler, Application.Acti KeyboardVisibilityPlugin(Registrar registrar) { - this.registrar = registrar; + this.registrar = registrar; eventsSink = null; } + public static void registerWith(Registrar registrar) { + + final EventChannel eventChannel = new EventChannel(registrar.messenger(), STREAM_CHANNEL_NAME); + KeyboardVisibilityPlugin instance = new KeyboardVisibilityPlugin(registrar); + eventChannel.setStreamHandler(instance); + Application application = registrar.activity().getApplication(); + application.registerActivityLifecycleCallbacks(instance); + // 引擎是在resume的时候初始化的,所以当第一个打开的页面是flutteractivity时,onResume监听不会回调,需要手动注册,这只是临时方案 + // 把插件注册方式升级到v2就可以了 + try{ + Activity activity = registrar.activity(); + if (instance.checkIsFlutterActivity(activity)){ + View mainView = ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); + mainView.getViewTreeObserver().addOnGlobalLayoutListener(instance); + instance.setMainView(mainView); + } + } catch (Exception e){ + e.printStackTrace(); + } + } + + public void setMainView(View mainView) { + this.mainView = mainView; + } + @Override public void onGlobalLayout() { Rect r = new Rect(); if (mainView != null) { - mainView.getWindowVisibleDisplayFrame(r); - - // check if the visible part of the screen is less than 85% - // if it is then the keyboard is showing - boolean newState = ((double)r.height() / (double)mainView.getRootView().getHeight()) < 0.85; - - if (newState != isVisible) { - isVisible = newState; - if (eventsSink != null) { - eventsSink.success(isVisible ? 1 : 0); - } - } - } + mainView.getWindowVisibleDisplayFrame(r); + + // check if the visible part of the screen is less than 85% + // if it is then the keyboard is showing + boolean newState = ((double) r.height() / (double) mainView.getRootView().getHeight()) < 0.85; + + if (newState != isVisible) { + isVisible = newState; + if (eventsSink != null) { + eventsSink.success(isVisible ? 1 : 0); + } + } + } } @Override public void onActivityCreated(Activity activity, Bundle bundle) { + } @Override public void onActivityStarted(Activity activity) { - try { - mainView = ((ViewGroup)activity.findViewById(android.R.id.content)).getChildAt(0); - mainView.getViewTreeObserver().addOnGlobalLayoutListener(this); - } - catch (Exception e) { - // do nothing - } + } @Override public void onActivityResumed(Activity activity) { + if (!checkIsFlutterActivity(activity)) { + return; + } + try { + mainView = ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); + mainView.getViewTreeObserver().addOnGlobalLayoutListener(this); + } catch (Exception e) { + // do nothing + } } @Override public void onActivityPaused(Activity activity) { + if (!checkIsFlutterActivity(activity)) { + return; + } + unregisterListener(activity); } @Override public void onActivityStopped(Activity activity) { - unregisterListener(); + } @Override @@ -87,24 +115,41 @@ public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { @Override public void onActivityDestroyed(Activity activity) { - - unregisterListener(); } - private void unregisterListener() { - if (mainView != null) { - mainView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + private void unregisterListener(Activity activity) { + if (activity != null) { + View currentMainView = getMainView(activity); + if (currentMainView != null) { + currentMainView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } mainView = null; } } - public static void registerWith(Registrar registrar) { + public View getMainView(Activity activity) { + return ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0); + } - final EventChannel eventChannel = new EventChannel(registrar.messenger(), STREAM_CHANNEL_NAME); - KeyboardVisibilityPlugin instance = new KeyboardVisibilityPlugin(registrar); - eventChannel.setStreamHandler(instance); + public boolean checkIsFlutterActivity(Activity activity) { + return findFlutterView(getMainView(activity)); + } - registrar.activity().getApplication().registerActivityLifecycleCallbacks(instance); + public boolean findFlutterView(View contentView) { + boolean hasFlutterView = false; + if (contentView instanceof ViewGroup) { + ViewGroup parentView = (ViewGroup) contentView; + for (int index = 0; index < parentView.getChildCount(); index++) { + hasFlutterView = findFlutterView(parentView.getChildAt(index)); + if (hasFlutterView) { + break; + } + } + } + if (contentView instanceof View && !hasFlutterView) { + hasFlutterView = contentView instanceof FlutterView; + } + return hasFlutterView; } @Override diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..ae1f183 --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,37 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index f97cd40..d7f2d8e 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 27 + compileSdkVersion 28 lintOptions { disable 'InvalidPackage' @@ -35,7 +35,7 @@ android { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.github.adee42.keyboardvisibilityexample" minSdkVersion 16 - targetSdkVersion 27 + targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index 592ceee..e8efba1 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Generated.xcconfig b/example/ios/Flutter/Generated.xcconfig new file mode 100644 index 0000000..04f862e --- /dev/null +++ b/example/ios/Flutter/Generated.xcconfig @@ -0,0 +1,10 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=/Users/weidian215/Library/Flutter/1.17.0+wd002/flutter +FLUTTER_APPLICATION_PATH=/Users/weidian215/flutter_keyboard_visibility/example +FLUTTER_TARGET=lib/main.dart +FLUTTER_BUILD_DIR=build +SYMROOT=${SOURCE_ROOT}/../build/ios +OTHER_LDFLAGS=$(inherited) -framework Flutter +FLUTTER_FRAMEWORK_DIR=/Users/weidian215/Library/Flutter/1.17.0+wd002/flutter/bin/cache/artifacts/engine/ios +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 592ceee..399e934 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/flutter_export_environment.sh b/example/ios/Flutter/flutter_export_environment.sh new file mode 100755 index 0000000..bef7186 --- /dev/null +++ b/example/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=/Users/weidian215/Library/Flutter/1.17.0+wd002/flutter" +export "FLUTTER_APPLICATION_PATH=/Users/weidian215/flutter_keyboard_visibility/example" +export "FLUTTER_TARGET=lib/main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build/ios" +export "OTHER_LDFLAGS=$(inherited) -framework Flutter" +export "FLUTTER_FRAMEWORK_DIR=/Users/weidian215/Library/Flutter/1.17.0+wd002/flutter/bin/cache/artifacts/engine/ios" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..5a69b89 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,84 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/example/ios/Runner/GeneratedPluginRegistrant.h b/example/ios/Runner/GeneratedPluginRegistrant.h new file mode 100644 index 0000000..ed9a5c6 --- /dev/null +++ b/example/ios/Runner/GeneratedPluginRegistrant.h @@ -0,0 +1,17 @@ +// +// Generated file. Do not edit. +// + +#ifndef GeneratedPluginRegistrant_h +#define GeneratedPluginRegistrant_h + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GeneratedPluginRegistrant : NSObject ++ (void)registerWithRegistry:(NSObject*)registry; +@end + +NS_ASSUME_NONNULL_END +#endif /* GeneratedPluginRegistrant_h */ diff --git a/example/ios/Runner/GeneratedPluginRegistrant.m b/example/ios/Runner/GeneratedPluginRegistrant.m new file mode 100644 index 0000000..7a5c7aa --- /dev/null +++ b/example/ios/Runner/GeneratedPluginRegistrant.m @@ -0,0 +1,19 @@ +// +// Generated file. Do not edit. +// + +#import "GeneratedPluginRegistrant.h" + +#if __has_include() +#import +#else +@import keyboard_visibility; +#endif + +@implementation GeneratedPluginRegistrant + ++ (void)registerWithRegistry:(NSObject*)registry { + [FLTKeyboardVisibilityPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTKeyboardVisibilityPlugin"]]; +} + +@end diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..0f14037 --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,51 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + keyboard_visibility: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.5.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" +sdks: + dart: ">=2.2.2 <3.0.0" + flutter: ">=0.1.4 <2.0.0" diff --git a/lib/keyboard_visibility.dart b/lib/keyboard_visibility_hybrid.dart similarity index 100% rename from lib/keyboard_visibility.dart rename to lib/keyboard_visibility_hybrid.dart diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..2a03220 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,44 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" +sdks: + dart: ">=2.2.2 <3.0.0" + flutter: ">=0.1.4 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3abbc64..de43004 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,10 @@ -name: keyboard_visibility -description: Flutter plugin for discovering the state of the soft-keyboard visibility on Android and iOS. -version: 0.5.6 -author: adee42 <42adee@gmail.com> -homepage: https://github.com/adee42/flutter_keyboard_visibility/tree/master +name: keyboard_visibility_hybrid +description: Flutter plugin for discovering the state of the soft-keyboard visibility on Android and iOS. adapter hybrid. +version: 0.0.1 +homepage: https://github.com/allenyulun/flutter_keyboard_visibility environment: - sdk: ">=2.0.0-dev.68.0 <3.0.0" - flutter: ">=0.1.4 <2.0.0" + sdk: ">=2.2.0 <3.0.0" dependencies: flutter: