├── tools_plugin ├── ios │ ├── Assets │ │ └── .gitkeep │ ├── Classes │ │ ├── DebugtoolsPlugin.h │ │ └── DebugtoolsPlugin.m │ ├── .gitignore │ └── k_debug_tools.podspec ├── android │ ├── settings.gradle │ ├── gradle.properties │ ├── .gitignore │ ├── src │ │ └── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── kwai │ │ │ │ └── flutter │ │ │ │ └── debugtools │ │ │ │ └── screen │ │ │ │ ├── FrameInfo.java │ │ │ │ └── FpsHelper.java │ │ │ └── kotlin │ │ │ └── com │ │ │ └── kwai │ │ │ └── flutter │ │ │ └── debugtools │ │ │ └── DebugtoolsPlugin.kt │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── build.gradle ├── example │ ├── ios │ │ ├── Flutter │ │ │ ├── .last_build_id │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ └── AppFrameworkInfo.plist │ │ ├── Runner │ │ │ ├── Runner-Bridging-Header.h │ │ │ ├── Assets.xcassets │ │ │ │ ├── LaunchImage.imageset │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ ├── README.md │ │ │ │ │ └── Contents.json │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ │ └── Contents.json │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj │ │ │ │ ├── Main.storyboard │ │ │ │ └── LaunchScreen.storyboard │ │ │ └── Info.plist │ │ ├── Runner.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── .gitignore │ │ └── Podfile │ ├── android │ │ ├── gradle.properties │ │ ├── .gitignore │ │ ├── app │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── drawable │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ └── values │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── kotlin │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── kwai │ │ │ │ │ │ │ └── flutter │ │ │ │ │ │ │ └── debugtools_example │ │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── debug │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── profile │ │ │ │ │ └── AndroidManifest.xml │ │ │ └── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ ├── settings.gradle │ │ └── build.gradle │ ├── .metadata │ ├── README.md │ ├── .gitignore │ ├── lib │ │ ├── demo_serv_config.dart │ │ └── main.dart │ └── pubspec.yaml ├── CHANGELOG.md ├── .metadata ├── lib │ ├── src │ │ ├── model │ │ │ ├── base_model.dart │ │ │ ├── web_socket_models.dart │ │ │ └── photo_models.dart │ │ ├── serverconfig │ │ │ └── server_config_models.dart │ │ ├── logwatcher │ │ │ ├── log_models.dart │ │ │ └── log_watcher_controller.dart │ │ ├── webserver │ │ │ ├── handlers │ │ │ │ ├── pin_handler.dart │ │ │ │ ├── clip_board_handler.dart │ │ │ │ ├── logwatcher_handler.dart │ │ │ │ ├── app_info_handler.dart │ │ │ │ └── sp_handler.dart │ │ │ └── handler_def.dart │ │ ├── fileexplorer │ │ │ └── file_explorer_models.dart │ │ ├── navigator │ │ │ └── navigator_models.dart │ │ ├── widgets │ │ │ ├── toast.dart │ │ │ ├── progress_dialog.dart │ │ │ ├── floating_button.dart │ │ │ └── dialog.dart │ │ ├── uicheck │ │ │ └── uicheck_models.dart │ │ ├── http │ │ │ ├── httparchive │ │ │ │ ├── http_request_widget.dart │ │ │ │ ├── http_response_widget.dart │ │ │ │ └── http_archive_detail_page.dart │ │ │ └── httphook │ │ │ │ ├── config_provider.dart │ │ │ │ └── http_hook_controller.dart │ │ └── appinfo │ │ │ └── app_info.dart │ └── k_debug_tools.dart ├── pubspec.yaml └── README.md ├── tools_web ├── web │ ├── favicon.png │ ├── icons │ │ ├── Icon-192.png │ │ └── Icon-512.png │ ├── manifest.json │ └── index.html ├── l10n.yaml ├── CHANGELOG.md ├── .metadata ├── README.md ├── lib │ ├── src │ │ ├── event │ │ │ └── PinEvent.dart │ │ ├── event_bus.dart │ │ ├── custom_color.dart │ │ ├── app │ │ │ ├── dbview │ │ │ │ └── db_events.dart │ │ │ ├── sharedpreferences │ │ │ │ └── shared_preferences_models.dart │ │ │ ├── logwatcher │ │ │ │ └── log_models.dart │ │ │ ├── model.dart │ │ │ ├── videoplayer │ │ │ │ ├── video_player_bloc.dart │ │ │ │ └── video_player.dart │ │ │ ├── fileexplorer │ │ │ │ └── file_explorer_models.dart │ │ │ ├── appinfo │ │ │ │ └── app_info_bloc.dart │ │ │ ├── deviceinfo │ │ │ │ └── device_info_bloc.dart │ │ │ ├── clipboard │ │ │ │ └── clip_board_bloc.dart │ │ │ ├── texteditor │ │ │ │ └── text_editor_bloc.dart │ │ │ ├── photomanager │ │ │ │ ├── photo_models.dart │ │ │ │ ├── asset_preview_bloc.dart │ │ │ │ └── widgets │ │ │ │ │ ├── asset_item_thumb.dart │ │ │ │ │ └── album_tree.dart │ │ │ ├── imagepreview │ │ │ │ └── image_preview_bloc.dart │ │ │ ├── pagenavigator │ │ │ │ └── page_navigator_models.dart │ │ │ ├── uicheck │ │ │ │ ├── uicheck_bloc.dart │ │ │ │ └── uicheck_models.dart │ │ │ ├── httphook │ │ │ │ └── widgets │ │ │ │ │ └── http_hook_domain_tree.dart │ │ │ └── httphookconfig │ │ │ │ └── hook_config_bloc.dart │ │ ├── ui │ │ │ └── theme.dart │ │ ├── web_http.dart │ │ ├── websocket │ │ │ └── web_socket_models.dart │ │ ├── bloc_provider.dart │ │ └── widgets │ │ │ ├── toast.dart │ │ │ └── flutter_cursor │ │ │ └── flutter_cursor.dart │ └── l10n │ │ ├── app_zh.arb │ │ └── app_en.arb ├── pubspec.yaml └── test │ └── widget_test.dart ├── CHANGELOG.md ├── README_CN.md ├── .gitignore ├── README.md └── docs └── INTEGRATION.md /tools_plugin/ios/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools_plugin/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'debugtools' 2 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Flutter/.last_build_id: -------------------------------------------------------------------------------- 1 | a9a03d916e3ef114d08bdd1a80fb0df6 -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /tools_web/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_web/web/favicon.png -------------------------------------------------------------------------------- /tools_web/l10n.yaml: -------------------------------------------------------------------------------- 1 | arb-dir: lib/l10n 2 | template-arb-file: app_en.arb 3 | output-localization-file: app_localizations.dart -------------------------------------------------------------------------------- /tools_web/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_web/web/icons/Icon-192.png -------------------------------------------------------------------------------- /tools_web/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_web/web/icons/Icon-512.png -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.3 2 | * feature: PhotoManager 3 | 4 | ## 1.0.2 5 | * localization. 6 | 7 | ## 1.0.1 8 | * initial release. -------------------------------------------------------------------------------- /tools_web/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.3 2 | * feature: PhotoManager 3 | 4 | ## 1.0.2 5 | * localization. 6 | 7 | ## 1.0.1 8 | * initial release. -------------------------------------------------------------------------------- /tools_plugin/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.3 2 | * feature: PhotoManager 3 | 4 | ## 1.0.2 5 | * localization. 6 | 7 | ## 1.0.1 8 | * initial release. -------------------------------------------------------------------------------- /tools_plugin/ios/Classes/DebugtoolsPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface DebugtoolsPlugin : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /tools_plugin/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /tools_plugin/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /tools_plugin/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /tools_plugin/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /tools_plugin/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KwaiAppTeam/KDebugTools/HEAD/tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/kotlin/com/kwai/flutter/debugtools_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.kwai.flutter.debugtools_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /tools_plugin/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 6 | -------------------------------------------------------------------------------- /tools_plugin/ios/Classes/DebugtoolsPlugin.m: -------------------------------------------------------------------------------- 1 | #import "DebugtoolsPlugin.h" 2 | 3 | 4 | @implementation DebugtoolsPlugin 5 | + (void)registerWithRegistrar:(NSObject*)registrar { 6 | //[SwiftDebugtoolsPlugin registerWithRegistrar:registrar]; 7 | } 8 | @end 9 | -------------------------------------------------------------------------------- /tools_plugin/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tools_web/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1ad9baa8b99a2897c20f9e6e54d3b9b359ade314 8 | channel: unknown 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /tools_plugin/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1ad9baa8b99a2897c20f9e6e54d3b9b359ade314 8 | channel: unknown 9 | 10 | project_type: plugin 11 | -------------------------------------------------------------------------------- /tools_plugin/example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 1ad9baa8b99a2897c20f9e6e54d3b9b359ade314 8 | channel: unknown 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tools_web/README.md: -------------------------------------------------------------------------------- 1 | ## What is this? 2 | 3 | This is a Flutter web project that provide a suite of tools via browser for 4 | KDebugTools plugin. 5 | 6 | ## Getting started 7 | 8 | This project has been integrated by KDebugTools plugin by default. 9 | 10 | ## Warning 11 | 12 | Web tools of this project uses Google Analytics to anonymously report 13 | feature usage statistics. This data is used to help improve this project 14 | over time. -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tools_plugin/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /tools_plugin/example/README.md: -------------------------------------------------------------------------------- 1 | # debugtools_example 2 | 3 | Demonstrates how to use the debugtools plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /tools_web/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "short_name": "web", 4 | "start_url": ".", 5 | "display": "minimal-ui", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter application.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /tools_web/lib/src/event/PinEvent.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class PinVerified {} 16 | -------------------------------------------------------------------------------- /tools_plugin/example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | // Copyright 2014 The Flutter Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | include ':app' 6 | 7 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 8 | def properties = new Properties() 9 | 10 | assert localPropertiesFile.exists() 11 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 12 | 13 | def flutterSdkPath = properties.getProperty("flutter.sdk") 14 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 15 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 16 | -------------------------------------------------------------------------------- /tools_plugin/example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /tools_web/lib/src/event_bus.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:event_bus/event_bus.dart'; 16 | 17 | EventBus eventBus = EventBus(); 18 | -------------------------------------------------------------------------------- /tools_web/lib/src/custom_color.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:ui'; 16 | 17 | class CustomColor { 18 | static const Color iconActionRed = Color(0xffba5b54); 19 | static const Color iconActionGreen = Color(0xff5f995c); 20 | } 21 | -------------------------------------------------------------------------------- /tools_plugin/example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Symbolication related 37 | app.*.symbols 38 | 39 | # Obfuscation related 40 | app.*.map.json 41 | 42 | # Exceptions to above rules. 43 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 44 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/dbview/db_events.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:k_debug_tools_web/src/widgets/tree.dart'; 16 | 17 | import 'db_view_models.dart'; 18 | 19 | class DbTreeNodeDoubleClick { 20 | Node node; 21 | 22 | DbTreeNodeDoubleClick(this.node); 23 | } 24 | 25 | class NewQueryClick { 26 | DbFile dbFile; 27 | 28 | NewQueryClick(this.dbFile); 29 | } 30 | -------------------------------------------------------------------------------- /tools_plugin/ios/k_debug_tools.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint k_debug_tools.podspec' to validate before publishing. 4 | # 5 | Pod::Spec.new do |s| 6 | s.name = 'k_debug_tools' 7 | s.version = '1.0.0' 8 | s.summary = 'A new Flutter plugin.' 9 | s.description = <<-DESC 10 | A new Flutter plugin. 11 | DESC 12 | s.homepage = 'http://example.com' 13 | s.license = { :file => '../LICENSE' } 14 | s.author = { 'Your Company' => 'email@example.com' } 15 | s.source = { :path => '.' } 16 | s.source_files = 'Classes/**/*' 17 | s.dependency 'Flutter' 18 | s.platform = :ios, '8.0' 19 | 20 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. 21 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } 22 | s.swift_version = '5.0' 23 | end 24 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/model/base_model.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class BaseKeyValue { 16 | String key; 17 | String value; 18 | 19 | BaseKeyValue(this.key, this.value); 20 | 21 | Map toJson() { 22 | Map result = Map(); 23 | result['key'] = key; 24 | result['value'] = value; 25 | return result; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tools_web/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: k_debug_tools_web 2 | description: Web tools for KDebugTools. 3 | 4 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 5 | 6 | version: 1.0.3 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | flutter_localizations: 15 | sdk: flutter 16 | uuid: ^2.2.2 17 | cupertino_icons: ^1.0.2 18 | http: ^0.12.2 19 | oktoast: ^2.3.2 20 | intl: ^0.17.0 21 | rxdart: ^0.25.0 22 | web_socket_channel: ^1.2.0 23 | event_bus: ^1.1.1 24 | cached_network_image: ^2.5.0 25 | #video player 26 | chewie: ^0.12.1+1 27 | video_player: ^1.0.1 28 | video_player_web: ^0.1.4+1 29 | pin_code_fields: ^6.1.0 30 | shared_preferences: ^0.5.12+4 31 | shared_preferences_web: ^0.1.0 32 | visibility_detector: ^0.1.5 33 | provider: ^4.3.2+2 34 | firebase_analytics: ^7.0.1 35 | dev_dependencies: 36 | flutter_test: 37 | sdk: flutter 38 | 39 | 40 | flutter: 41 | generate: true 42 | uses-material-design: true -------------------------------------------------------------------------------- /tools_plugin/lib/k_debug_tools.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | export 'src/serverconfig/server_config_models.dart'; 16 | export 'src/debugger.dart'; 17 | export 'src/register.dart'; 18 | export 'src/widgets/list_widgets.dart'; 19 | export 'src/widgets/common_widgets.dart'; 20 | export 'src/serverconfig/server_config.dart'; 21 | export 'src/http/network_debugger.dart'; 22 | export 'src/model/localization_options.dart'; 23 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/serverconfig/server_config_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class ServerEnvConfig { 16 | ///0、1、2、3...用于选中后返回的值 17 | final int index; 18 | 19 | ///显示的名称 20 | final String name; 21 | 22 | ///是否可编辑env 23 | final bool canEdit; 24 | 25 | ///变量 26 | final Map envs; 27 | 28 | const ServerEnvConfig( 29 | {this.index, this.name, this.canEdit = false, this.envs}); 30 | } 31 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /tools_plugin/android/src/main/java/com/kwai/flutter/debugtools/screen/FrameInfo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Kwai, Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.kwai.flutter.debugtools.screen; 18 | 19 | import android.graphics.Bitmap; 20 | 21 | public class FrameInfo { 22 | public Bitmap bitmap; 23 | public long frameTs; 24 | 25 | FrameInfo(long frameTs, Bitmap bitmap) { 26 | this.frameTs = frameTs; 27 | this.bitmap = bitmap; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/sharedpreferences/shared_preferences_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class SpModel { 16 | String key; 17 | String value; 18 | final String valueType; 19 | 20 | SpModel({this.key, this.value, this.valueType}); 21 | 22 | static fromMap(Map map) { 23 | SpModel model = SpModel( 24 | key: map['key'] ?? '', 25 | value: map['value']?.toString() ?? '', 26 | valueType: map['valueType'] ?? ''); 27 | return model; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tools_web/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:k_debug_tools_web/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /tools_plugin/android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.kwai.flutter.debugtools' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | ext.kotlin_version = '1.3.50' 6 | repositories { 7 | google() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.5.0' 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | rootProject.allprojects { 18 | repositories { 19 | google() 20 | jcenter() 21 | } 22 | } 23 | 24 | apply plugin: 'com.android.library' 25 | apply plugin: 'kotlin-android' 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | sourceSets { 31 | main.java.srcDirs += 'src/main/kotlin' 32 | main.java.srcDirs += 'src/main/java' 33 | } 34 | defaultConfig { 35 | minSdkVersion 21 36 | } 37 | lintOptions { 38 | disable 'InvalidPackage' 39 | } 40 | compileOptions { 41 | sourceCompatibility = '1.8' 42 | targetCompatibility = '1.8' 43 | } 44 | } 45 | 46 | dependencies { 47 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 48 | implementation 'androidx.annotation:annotation:1.1.0' 49 | implementation 'androidx.core:core:1.1.0' 50 | } 51 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # KDebugTools 2 | 3 | KDebugTools是一套适用于Flutter平台的移动端应用研发辅助工具 4 | 5 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/webzh.jpg) 6 | 7 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/pluginzh.jpg) 8 | 9 | ### 通过内置的Web服务,可在电脑浏览器实现以下功能 10 | 11 | * App和设备信息查询 12 | * 设备文件管理、传输和预览 13 | * SharedPreference、SQLite直接查询和修改 14 | * Flutter网络抓包拦截及限流配置 15 | * Flutter日志查看 16 | * Flutter Widget属性检查 17 | * Flutter路由跳转 18 | * 设备剪切板同步 19 | * 设备投屏及录制(Android) 20 | 21 | ### 所有功能无需ROOT,无需USB连接 22 | 23 | ## 接入方法 24 | 25 | ### 添加依赖 26 | 27 | ```yaml 28 | ... 29 | dependencies: 30 | ... 31 | k_debug_tools: ^1.0.0 32 | ... 33 | ... 34 | ``` 35 | 36 | ### 初始化 37 | 38 | 参考 [example](tools_plugin/example/lib/main.dart) 39 | 40 | 导入 `package:k_debug_tools/k_debug_tools.dart`. 41 | 42 | ```dart 43 | ... 44 | Debugger.instance.init( 45 | autoStartWebServer: true, 46 | autoStartHttpHook: true); 47 | ... 48 | ``` 49 | 50 | ### 显示浮动按钮 51 | 52 | ```dart 53 | ... 54 | Debugger.instance.showDebugger(context); 55 | ... 56 | ``` 57 | 58 | ### 显示面板 59 | 60 | ```dart 61 | ... 62 | Debugger.instance.showDebuggerDialog(context); 63 | ... 64 | ``` 65 | 66 | ## 隐私说明 67 | 68 | 本项目在Web工具中会使用Google 69 | Analytics进行匿名数据收集,用于数据分析,旨在改善并促进项目发展 70 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/logwatcher/log_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | enum LogLevel { error, warn, info, debug, verbose } 16 | 17 | class LogEntry { 18 | int level; //0-5: 19 | int time; 20 | String msg; 21 | 22 | LogEntry({this.level, this.time, this.msg}); 23 | 24 | LogEntry.fromJson(Map json) { 25 | level = json['level']; 26 | time = json['time']; 27 | msg = json['msg']; 28 | } 29 | 30 | Map toJson() { 31 | final Map data = new Map(); 32 | data['level'] = this.level; 33 | data['time'] = this.time; 34 | data['msg'] = this.msg; 35 | return data; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/logwatcher/log_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | const LogLevelTag = ['E', 'W', 'I', 'D', 'V']; 16 | enum LogLevel { 17 | error, 18 | warn, 19 | info, 20 | debug, 21 | verbose, 22 | } 23 | 24 | class LogEntry { 25 | int level; //0-5: 26 | int time; 27 | String msg; 28 | 29 | LogEntry({this.level, this.time, this.msg}); 30 | 31 | LogEntry.fromJson(Map json) { 32 | level = json['level']; 33 | time = json['time']; 34 | msg = json['msg']; 35 | } 36 | 37 | Map toJson() { 38 | final Map data = new Map(); 39 | data['level'] = this.level; 40 | data['time'] = this.time; 41 | data['msg'] = this.msg; 42 | return data; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/model.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class ErrorResult { 16 | String message; 17 | int respCode; 18 | String respMessage; 19 | 20 | ErrorResult.create(String msg, Map respMap) { 21 | message = msg; 22 | respCode = respMap['code']; 23 | respMessage = respMap['message']; 24 | } 25 | 26 | @override 27 | String toString() { 28 | return '$message: $respCode#$respMessage'; 29 | } 30 | } 31 | 32 | class BaseKeyValue { 33 | String key; 34 | String value; 35 | 36 | BaseKeyValue(this.key, this.value); 37 | 38 | Map toJson() { 39 | Map result = Map(); 40 | result['key'] = key; 41 | result['value'] = value; 42 | return result; 43 | } 44 | 45 | BaseKeyValue.fromMap(Map map) { 46 | key = map['key']; 47 | value = map['value']; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tools_plugin/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: k_debug_tools 2 | description: KDebugTools is a powerful library for debugging Flutter applications. 3 | version: 1.0.3 4 | homepage: https://github.com/KwaiAppTeam/KDebugTools 5 | level: utility 6 | publish_to: 'https://pub.dev' 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | flutter: ">=1.10.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | uuid: ^2.0.0 17 | device_info: ^0.4.2+4 18 | shared_preferences: ^0.5.7+3 19 | package_info: '>=0.4.0+16 <2.0.0' 20 | #web服务 21 | http_server: ^0.9.8+3 22 | http_multi_server: ^2.2.0 23 | web_socket_channel: ^1.2.0 24 | stream_channel: ^2.0.0 25 | convert: ^2.0.2 26 | crypto: ^2.0.0 27 | http_parser: ^3.1.0 28 | path: ^1.7.0 29 | intl: ^0.16.0 30 | mime: ^0.9.7 31 | shelf: ^0.7.9 32 | shelf_static: ^0.2.8 33 | shelf_router: ^0.7.2 34 | shelf_web_socket: ^0.2.3 35 | #静态资源代理到cdn上减少包体积 36 | shelf_proxy: ^0.1.0+7 37 | #uri工具集用于uri匹配 38 | uri: ^0.11.3+1 39 | #读文件 40 | path_provider: ^1.6.14 41 | #压缩文件 42 | archive: ^2.0.13 43 | #toast 44 | oktoast: ^2.3.2 45 | #数据库 46 | sqflite: ^1.3.1 47 | wifi_info_flutter: ^1.0.3 48 | photo_manager: ^0.6.0 49 | dev_dependencies: 50 | flutter_test: 51 | sdk: flutter 52 | 53 | flutter: 54 | plugin: 55 | platforms: 56 | android: 57 | package: com.kwai.flutter.debugtools 58 | #todo 临时用这个 整理后挪走 59 | pluginClass: ScreenPreviewPlugin 60 | ios: 61 | pluginClass: DebugtoolsPlugin 62 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handlers/pin_handler.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | 18 | import 'package:k_debug_tools/src/webserver/web_server.dart'; 19 | import 'package:shelf/shelf.dart'; 20 | import 'package:shelf_router/shelf_router.dart' as shelf; 21 | 22 | import '../handler_def.dart'; 23 | 24 | class PinHandler extends AbsAppHandler { 25 | @override 26 | shelf.Router get router { 27 | final router = shelf.Router(); 28 | router.post('/check', _check); 29 | router.all('/', (Request request) => notFound()); 30 | return router; 31 | } 32 | 33 | Future _check(Request request) async { 34 | Map body = jsonDecode(await request.readAsString()); 35 | String pin = body['pin']; 36 | if (pin == WebServer.instance.pin) { 37 | return ok(); 38 | } 39 | return error('PIN Error'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/videoplayer/video_player_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'dart:html' as html; 18 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 19 | import 'package:k_debug_tools_web/src/web_http.dart'; 20 | 21 | import '../model.dart'; 22 | 23 | class VideoPlayerBloc extends AppBlocBase { 24 | //路径和文件api一样 25 | static const String PATH = 'api/file'; 26 | 27 | //文本路径或者url 28 | final String filePath; 29 | 30 | bool _deleted = false; 31 | 32 | String get networkPath => filePath.startsWith('http') 33 | ? filePath 34 | : '${getHostWithSchema()}/$PATH/read$filePath?Token=${getToken()}'; 35 | 36 | bool get canDownload => !_deleted && filePath != null; 37 | 38 | VideoPlayerBloc(context, this.filePath) : super(context); 39 | 40 | @override 41 | void dispose() {} 42 | 43 | bool get hasFilePath => filePath?.isNotEmpty == true; 44 | } 45 | -------------------------------------------------------------------------------- /tools_plugin/example/lib/demo_serv_config.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:k_debug_tools/k_debug_tools.dart'; 16 | 17 | ///定义所有需要配置的环境key 18 | const List EnvKeys = ['BIZ_URL', 'PASSPORT_URL', 'other']; 19 | 20 | ///定义所有环境 21 | const List ServerConfigs = [ 22 | ServerEnvConfig(index: 0, name: '线上环境', canEdit: false, envs: { 23 | 'PASSPORT_URL': 'https://passport.demo.com', 24 | 'BIZ_URL': 'https://biz.demo.com', 25 | 'other': 'someConfigs' 26 | }), 27 | ServerEnvConfig(index: 1, name: '测试环境1', canEdit: true, envs: { 28 | 'PASSPORT_URL': 'https://passport-tst.demo.com', 29 | 'BIZ_URL': 'https://biz-test.demo.com', 30 | 'other': 'someConfigs' 31 | }), 32 | ServerEnvConfig(index: 2, name: '测试环境2', canEdit: true, envs: { 33 | 'PASSPORT_URL': 'https://passport-custom.demo.com', 34 | 'BIZ_URL': 'https://passport-custom.demo.com', 35 | 'other': 'someConfigs' 36 | }), 37 | ServerEnvConfig(index: 3, name: '自定义', canEdit: true, envs: {}), 38 | ]; 39 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | target.build_configurations.each do |config| 41 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X 2 | *.DS_Store 3 | .fvm 4 | .vscode 5 | # node 6 | node_modules 7 | 8 | # build 目录 9 | build 10 | # 打包输出文件 11 | dist 12 | 13 | # Flutter/Dart/Pub related 14 | **/doc/api/ 15 | .dart_tool/ 16 | .flutter-plugins 17 | .flutter-plugins-dependencies 18 | .packages 19 | .pub-cache/ 20 | .pub/ 21 | build/ 22 | flutter_*.png 23 | linked_*.ds 24 | unlinked.ds 25 | unlinked_spec.ds 26 | 27 | # Android related 28 | **/android/.gradle 29 | **/android/captures/ 30 | **/android/local.properties 31 | **/android/**/GeneratedPluginRegistrant.java 32 | **/android/key.properties 33 | *.jks 34 | .idea/ 35 | android/.idea 36 | android/local.properties 37 | *.iml 38 | **/.settings/ 39 | **/.idea/ 40 | .gradle/ 41 | 42 | # iOS/XCode related 43 | **/ios/Pods/ 44 | **/ios/Podfile.lock 45 | **/ios/.generated/ 46 | **/ios/.symlinks/ 47 | **/ios/**/*.mode1v3 48 | **/ios/**/*.mode2v3 49 | **/ios/**/*.moved-aside 50 | **/ios/**/*.pbxuser 51 | **/ios/**/*.perspectivev3 52 | **/ios/**/*sync/ 53 | **/ios/**/.sconsign.dblite 54 | **/ios/**/.tags* 55 | **/ios/**/.vagrant/ 56 | **/ios/**/DerivedData/ 57 | **/ios/**/Icon? 58 | **/ios/**/Pods/ 59 | **/ios/**/.symlinks/ 60 | **/ios/**/profile 61 | **/ios/**/xcuserdata 62 | **/ios/Flutter/App.framework 63 | **/ios/Flutter/Flutter.framework 64 | **/ios/Flutter/Flutter.podspec 65 | **/ios/Flutter/Generated.xcconfig 66 | **/ios/Flutter/app.flx 67 | **/ios/Flutter/app.zip 68 | **/ios/Flutter/flutter_assets/ 69 | **/ios/Flutter/flutter_export_environment.sh 70 | **/ios/ServiceDefinitions.json 71 | **/ios/Runner/GeneratedPluginRegistrant.* 72 | .fvm/flutter_sdk 73 | .fvm/fvm_config.json 74 | **/ios/.gundam 75 | generated_plugin_registrant.dart 76 | pubspec.lock 77 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handlers/clip_board_handler.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'package:flutter/services.dart'; 18 | import 'package:shelf/shelf.dart'; 19 | import 'package:shelf_router/shelf_router.dart' as shelf; 20 | 21 | import '../handler_def.dart'; 22 | 23 | ///用于读取、写入手机剪切板 24 | class ClipBoardHandler extends AbsAppHandler { 25 | @override 26 | shelf.Router get router { 27 | final router = shelf.Router(); 28 | router.post('/read', _read); 29 | router.post('/write', _write); 30 | router.all('/', (Request request) => notFound()); 31 | return router; 32 | } 33 | 34 | Future _read(Request request) async { 35 | ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); 36 | return ok({'text': data?.text ?? ''}); 37 | } 38 | 39 | Future _write(Request request) async { 40 | Map body = jsonDecode(await request.readAsString()); 41 | String text = body['text']; 42 | await Clipboard.setData(ClipboardData(text: text)); 43 | return ok(null); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | debugtools_example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /tools_web/lib/src/ui/theme.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Chromium Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | import '../theme.dart'; 8 | 9 | const contrastForegroundWhite = Color.fromARGB(255, 240, 240, 240); 10 | 11 | extension DevToolsColorScheme on ColorScheme { 12 | bool get isLight => brightness == Brightness.light; 13 | 14 | bool get isDark => brightness == Brightness.dark; 15 | 16 | // Commonly used themed colors. 17 | Color get defaultBackground => isLight ? Colors.white : Colors.black; 18 | 19 | Color get defaultForeground => 20 | isLight ? Colors.black : const Color.fromARGB(255, 187, 187, 187); 21 | 22 | /// Text color [defaultForeground] is too gray, making it hard to read the text 23 | /// in dark theme. We should use a more white color for dark theme, but not 24 | /// jarring white #FFFFFF. 25 | Color get contrastForegroundWhite => const Color.fromARGB(255, 240, 240, 240); 26 | 27 | Color get contrastForeground => 28 | isLight ? Colors.black : contrastForegroundWhite; 29 | 30 | Color get grey => isLight 31 | ? const Color.fromARGB(255, 128, 128, 128) 32 | : const Color.fromARGB(255, 128, 128, 128); 33 | 34 | /// Background colors for charts. 35 | Color get chartBackground => isLight ? Colors.white : const Color(0xFF2D2E31); 36 | 37 | Color get defaultButtonIconColor => 38 | isLight ? const Color(0xFF24292E) : const Color(0xFF89B5F8); 39 | 40 | Color get defaultPrimaryButtonIconColor => defaultBackground; 41 | 42 | Color get defaultDesktopAppItemBackground => 43 | isLight ? devtoolsBlue[600] : devtoolsGrey[900]; 44 | } 45 | -------------------------------------------------------------------------------- /tools_plugin/android/src/main/java/com/kwai/flutter/debugtools/screen/FpsHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2021 Kwai, Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.kwai.flutter.debugtools.screen; 18 | 19 | import android.util.Log; 20 | 21 | import java.util.LinkedList; 22 | import java.util.List; 23 | 24 | /** 25 | * 用于统计fps 26 | */ 27 | public class FpsHelper { 28 | private String name; 29 | private final List frameTs = new LinkedList<>(); 30 | 31 | public FpsHelper(String name) { 32 | this.name = name; 33 | } 34 | 35 | public void addFrame() { 36 | frameTs.add(System.currentTimeMillis()); 37 | clearOldFrame(); 38 | } 39 | 40 | public void print() { 41 | clearOldFrame(); 42 | // Log.d("FpsHelper", name + ": " + frameTs.size()); 43 | } 44 | 45 | public int getFps() { 46 | clearOldFrame(); 47 | return frameTs.size(); 48 | } 49 | 50 | private void clearOldFrame() { 51 | for (; ; ) { 52 | //去除1s以前的数据 53 | if (frameTs.isEmpty() || System.currentTimeMillis() - frameTs.get(0) < 1000) { 54 | break; 55 | } 56 | frameTs.remove(0); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tools_web/lib/src/web_http.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | 17 | import 'package:http/http.dart' as http; 18 | 19 | String _pinCode = ''; 20 | 21 | String getPin() => _pinCode ?? ''; 22 | 23 | void setPin(pin) => _pinCode = pin; 24 | 25 | String _token = ''; 26 | 27 | String getToken() => _token ?? ''; 28 | 29 | void setToken(tk) => _token = tk; 30 | 31 | Future httpPost(url, 32 | {Map headers, body, Encoding encoding}) { 33 | headers ??= Map(); 34 | headers = _addPin(headers); 35 | if (!(body is List) && !(body is String)) { 36 | body = jsonEncode(body); 37 | headers['Content-Type'] = 'application/json; charset=utf-8'; 38 | } 39 | return http.post(url, headers: headers, body: body, encoding: encoding); 40 | } 41 | 42 | Future httpGet(url, 43 | {Map headers, body, Encoding encoding}) { 44 | headers = _addPin(headers); 45 | return http.get(url, headers: headers); 46 | } 47 | 48 | Map _addPin(Map headers) { 49 | if (_pinCode?.isNotEmpty ?? false) { 50 | headers ??= Map(); 51 | headers['Pin'] = _pinCode; 52 | } 53 | return headers; 54 | } 55 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handlers/logwatcher_handler.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | 18 | import 'package:flutter/cupertino.dart'; 19 | import 'package:k_debug_tools/src/logwatcher/log_watcher_controller.dart'; 20 | import 'package:shelf/shelf.dart'; 21 | import 'package:shelf_router/shelf_router.dart' as shelf; 22 | 23 | import '../handler_def.dart'; 24 | 25 | class LogWatcherHandler extends AbsAppHandler { 26 | @override 27 | shelf.Router get router { 28 | final router = shelf.Router(); 29 | 30 | router.post('/toggle', _toggle); 31 | router.get('/state', _state); 32 | 33 | router.all('/', (Request request) => notFound()); 34 | 35 | return router; 36 | } 37 | 38 | ///切换开关 39 | Future _toggle(Request request) async { 40 | Map body = jsonDecode(await request.readAsString()); 41 | bool enable = body['enable']; 42 | debugPrint('set LogWatcher to $enable'); 43 | LogWatcherController.instance.enable = enable; 44 | return ok(null); 45 | } 46 | 47 | ///读取状态 48 | Future _state(Request request) async { 49 | Map data = Map(); 50 | data['enable'] = LogWatcherController.instance.enable; 51 | return ok(data); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KDebugTools 2 | 3 | KDebugTools is a powerful library for debugging Flutter applications 4 | 5 | [Chinese](./README_CN.md) 6 | 7 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/web.jpg) 8 | 9 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/plugin.jpg) 10 | 11 | ### You can access these features via WebBrowser 12 | 13 | * Check App and device information 14 | * File management, transfer and preview 15 | * Directly edit the shared preferences or database values 16 | * Recording or throttling network with Flutter HttpClient 17 | * Fetch logs of application 18 | * View attributes of Flutter Widget 19 | * Controlling the Flutter navigator 20 | * Directly edit the device clipboard 21 | * Cast and record device screen (Android only) 22 | 23 | ### All these features work without rooting your device or USB connection 24 | 25 | ## Usage 26 | 27 | ### Import the package 28 | 29 | ```yaml 30 | ... 31 | dependencies: 32 | ... 33 | k_debug_tools: ^1.0.0 34 | ... 35 | ... 36 | ``` 37 | 38 | ### Use the plugin 39 | 40 | See the [`example`](tools_plugin/example) directory for a complete 41 | sample app using KDebugTools. 42 | 43 | You should be able to use `package:k_debug_tools` _almost_ as normal. 44 | 45 | First of all, you must init the plugin with code like this: 46 | 47 | ```dart 48 | ... 49 | Debugger.instance.init( 50 | autoStartWebServer: true, 51 | autoStartHttpHook: true); 52 | ... 53 | ``` 54 | 55 | ### Show floating button 56 | 57 | ```dart 58 | ... 59 | Debugger.instance.showDebugger(context); 60 | ... 61 | ``` 62 | 63 | ### Show debugger panel 64 | 65 | ```dart 66 | ... 67 | Debugger.instance.showDebuggerDialog(context); 68 | ... 69 | ``` 70 | 71 | ## Warning 72 | 73 | Web tools of this project uses Google Analytics to anonymously report 74 | feature usage statistics. This data is used to help improve this project 75 | over time. 76 | -------------------------------------------------------------------------------- /tools_plugin/README.md: -------------------------------------------------------------------------------- 1 | # KDebugTools 2 | 3 | KDebugTools is a powerful library for debugging Flutter applications 4 | 5 | [Chinese](https://github.com/KwaiAppTeam/KDebugTools/blob/main/README_CN.md) 6 | 7 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/web.jpg) 8 | 9 | ![Overview](https://static.yximgs.com/udata/pkg/KS-IDEA/k_debug_tools/readme/plugin.jpg) 10 | 11 | ### You can access these features via WebBrowser 12 | 13 | * Check App and device information 14 | * File management, transfer and preview 15 | * Directly edit the shared preferences or database values 16 | * Recording or throttling network with Flutter HttpClient 17 | * Fetch logs of application 18 | * View attributes of Flutter Widget 19 | * Controlling the Flutter navigator 20 | * Directly edit the device clipboard 21 | * Cast and record device screen (Android only) 22 | 23 | ### All these features work without rooting your device or USB connection 24 | 25 | ## Usage 26 | 27 | ### Import the package 28 | 29 | ```yaml 30 | ... 31 | dependencies: 32 | ... 33 | k_debug_tools: ^1.0.0 34 | ... 35 | ... 36 | ``` 37 | 38 | ### Use the plugin 39 | 40 | See the [`example`](example) directory for a complete 41 | sample app using KDebugTools. 42 | 43 | You should be able to use `package:k_debug_tools` _almost_ as normal. 44 | 45 | First of all, you must init the plugin with code like this: 46 | 47 | ```dart 48 | ... 49 | Debugger.instance.init( 50 | autoStartWebServer: true, 51 | autoStartHttpHook: true); 52 | ... 53 | ``` 54 | 55 | ### Show floating button 56 | 57 | ```dart 58 | ... 59 | Debugger.instance.showDebugger(context); 60 | ... 61 | ``` 62 | 63 | ### Show debugger panel 64 | 65 | ```dart 66 | ... 67 | Debugger.instance.showDebuggerDialog(context); 68 | ... 69 | ``` 70 | 71 | ## Warning 72 | 73 | Web tools of this project uses Google Analytics to anonymously report 74 | feature usage statistics. This data is used to help improve this project 75 | over time. 76 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/fileexplorer/file_explorer_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class FileModel { 16 | String name; 17 | String type; 18 | String absolute; 19 | int size; 20 | int lastModified; 21 | List subFiles; 22 | bool readOnly = false; 23 | 24 | FileModel( 25 | {this.name, 26 | this.type, 27 | this.absolute, 28 | this.size, 29 | this.subFiles, 30 | this.lastModified = 0, 31 | this.readOnly = false}); 32 | 33 | static fromMap(Map map) { 34 | FileModel model = FileModel(); 35 | model.name = map['name'] ?? ''; 36 | model.type = map['type'] ?? ''; 37 | model.absolute = map['absolute'] ?? ''; 38 | model.size = map['size']; 39 | model.lastModified = map['lastModified'] ?? 0; 40 | model.readOnly = map['readOnly'] ?? false; 41 | return model; 42 | } 43 | 44 | Map toJson() { 45 | Map result = Map(); 46 | result['name'] = name; 47 | result['type'] = type; 48 | result['absolute'] = absolute; 49 | result['size'] = size; 50 | result['lastModified'] = lastModified; 51 | result['readOnly'] = readOnly; 52 | return result; 53 | } 54 | 55 | bool get isDir => type == 'dir'; 56 | 57 | String get sizeStr => (size != null && size > 0) 58 | ? '${(size / 1024 / 1024).toStringAsFixed(2)}M' 59 | : ''; 60 | } 61 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/fileexplorer/file_explorer_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class FileModel { 16 | String name; 17 | String type; 18 | String absolute; 19 | int size; 20 | int lastModified; 21 | List subFiles; 22 | bool readOnly = false; 23 | 24 | FileModel( 25 | {this.name, 26 | this.type, 27 | this.absolute, 28 | this.size, 29 | this.subFiles, 30 | this.lastModified = 0, 31 | this.readOnly = false}); 32 | 33 | static fromMap(Map map) { 34 | FileModel model = FileModel(); 35 | model.name = map['name'] ?? ''; 36 | model.type = map['type'] ?? ''; 37 | model.absolute = map['absolute'] ?? ''; 38 | model.size = map['size']; 39 | model.lastModified = map['lastModified'] ?? 0; 40 | model.readOnly = map['readOnly'] ?? false; 41 | return model; 42 | } 43 | 44 | Map toJson() { 45 | Map result = Map(); 46 | result['name'] = name; 47 | result['type'] = type; 48 | result['absolute'] = absolute; 49 | result['size'] = size; 50 | result['lastModified'] = lastModified; 51 | result['readOnly'] = readOnly; 52 | return result; 53 | } 54 | 55 | bool get isDir => type == 'dir'; 56 | 57 | String get sizeStr => (size != null && size > 0) 58 | ? '${(size / 1024 / 1024).toStringAsFixed(2)}M' 59 | : ''; 60 | } 61 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.kwai.flutter.debugtools_example" 42 | minSdkVersion 21 43 | targetSdkVersion 22 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | ndk { abiFilters "arm64-v8a" } 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | } 65 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/model/web_socket_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | import 'dart:io'; 17 | 18 | import 'dart:typed_data'; 19 | 20 | class WsStat { 21 | final bool connected; 22 | 23 | WsStat(this.connected); 24 | } 25 | 26 | ///websocket的消息 27 | class WsMessage { 28 | String module; 29 | int cmd; 30 | ContentType type; 31 | Uint8List data; 32 | 33 | WsMessage({this.module, this.cmd, this.type, this.data}); 34 | 35 | static WsMessage fromJson(Map result) { 36 | if (result == null) { 37 | return null; 38 | } 39 | WsMessage message = WsMessage(); 40 | 41 | message.module = result['module']; 42 | message.cmd = result['cmd'] ?? 0; 43 | message.type = ContentType.parse(result['type'] ?? ''); 44 | if (result['data'] != null) { 45 | if (message.type == ContentType.binary) { 46 | message.data = base64Decode(result['data']); 47 | } else { 48 | message.data = utf8.encode(result['data']); 49 | } 50 | } 51 | return message; 52 | } 53 | 54 | Map toJson() { 55 | Map result = Map(); 56 | result['module'] = module; 57 | result['cmd'] = cmd; 58 | 59 | result['type'] = type.toString(); 60 | if (data != null) { 61 | if (type == ContentType.binary) { 62 | result['data'] = base64Encode(data); 63 | } else { 64 | result['data'] = utf8.decode(data); 65 | } 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/appinfo/app_info_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'package:flutter/cupertino.dart'; 17 | import 'package:flutter/material.dart'; 18 | import 'dart:convert' as convert; 19 | import 'package:flutter/widgets.dart'; 20 | import 'package:k_debug_tools_web/src/app/model.dart'; 21 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 22 | import 'package:k_debug_tools_web/src/web_http.dart'; 23 | 24 | class AppInfoBloc extends AppBlocBase { 25 | static const String PATH = 'api/app'; 26 | 27 | ///全局缓存 28 | static Map _data = Map(); 29 | 30 | Map get data => _data; 31 | 32 | String get appName => _data['appName'] ?? ''; 33 | 34 | AppInfoBloc(BuildContext context) : super(context); 35 | 36 | ///初始化数据 37 | Future> initData() async { 38 | if (_data.isNotEmpty) { 39 | return _data; 40 | } else { 41 | Uri uri = Uri.http(getHost(), '$PATH/info'); 42 | var response = await httpGet(uri); 43 | Map jsonResponse = convert.jsonDecode(response.body); 44 | if (response.statusCode == 200) { 45 | jsonResponse = (jsonResponse['data'] as Map); 46 | _data.addAll(jsonResponse); 47 | return _data; 48 | } else { 49 | return Future.error( 50 | ErrorResult.create('fetch data failed', jsonResponse)); 51 | } 52 | } 53 | } 54 | 55 | @override 56 | void dispose() { 57 | _data.clear(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tools_web/lib/src/websocket/web_socket_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | import 'dart:io'; 17 | 18 | import 'dart:typed_data'; 19 | 20 | class WsStat { 21 | final bool connected; 22 | 23 | WsStat(this.connected); 24 | } 25 | 26 | ///websocket的消息 27 | class WsMessage { 28 | String module; 29 | int cmd; 30 | ContentType type; 31 | Uint8List data; 32 | 33 | WsMessage({this.module, this.cmd, this.type, this.data}); 34 | 35 | static WsMessage fromJson(Map result) { 36 | if (result == null) { 37 | return null; 38 | } 39 | WsMessage message = WsMessage(); 40 | 41 | message.module = result['module']; 42 | message.cmd = result['cmd'] ?? 0; 43 | message.type = ContentType.parse(result['type'] ?? ''); 44 | if (result['data'] != null) { 45 | if (message.type == ContentType.binary) { 46 | message.data = base64Decode(result['data']); 47 | } else { 48 | message.data = utf8.encode(result['data']); 49 | } 50 | } 51 | return message; 52 | } 53 | 54 | Map toJson() { 55 | Map result = Map(); 56 | result['module'] = module; 57 | result['cmd'] = cmd; 58 | 59 | result['type'] = type.toString(); 60 | if (data != null) { 61 | if (type == ContentType.binary) { 62 | result['data'] = base64Encode(data); 63 | } else { 64 | result['data'] = utf8.decode(data); 65 | } 66 | } 67 | return result; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/deviceinfo/device_info_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'package:flutter/cupertino.dart'; 17 | import 'package:flutter/material.dart'; 18 | import 'dart:convert' as convert; 19 | import 'package:flutter/widgets.dart'; 20 | import 'package:k_debug_tools_web/src/app/model.dart'; 21 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 22 | import 'package:k_debug_tools_web/src/web_http.dart'; 23 | 24 | class DeviceInfoBloc extends AppBlocBase { 25 | static const String PATH = 'api/device'; 26 | 27 | ///全局缓存 28 | static Map _data = Map(); 29 | 30 | Map get data => _data; 31 | 32 | String get deviceName => _data['model'] ?? ''; 33 | 34 | DeviceInfoBloc(BuildContext context) : super(context); 35 | 36 | ///初始化数据 37 | Future> initData() async { 38 | if (_data.isNotEmpty) { 39 | return _data; 40 | } else { 41 | Uri uri = Uri.http(getHost(), '$PATH/info'); 42 | var response = await httpGet(uri); 43 | Map jsonResponse = convert.jsonDecode(response.body); 44 | if (response.statusCode == 200) { 45 | jsonResponse = (jsonResponse['data'] as Map); 46 | _data.addAll(jsonResponse); 47 | return _data; 48 | } else { 49 | return Future.error( 50 | ErrorResult.create('fetch data failed', jsonResponse)); 51 | } 52 | } 53 | } 54 | 55 | @override 56 | void dispose() { 57 | _data.clear(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/clipboard/clip_board_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'package:flutter/cupertino.dart'; 18 | import 'package:flutter/material.dart'; 19 | import 'package:flutter/widgets.dart'; 20 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 21 | import 'package:k_debug_tools_web/src/web_http.dart'; 22 | 23 | import '../model.dart'; 24 | 25 | class ClipBoardBloc extends AppBlocBase { 26 | static const String PATH = 'api/clipboard'; 27 | BuildContext context; 28 | 29 | ClipBoardBloc(this.context) : super(context); 30 | 31 | ///读取设备剪切板 32 | Future readFromDevice() async { 33 | Uri uri = Uri.http(getHost(), '$PATH/read'); 34 | var response = await httpPost(uri); 35 | if (response.statusCode == 200) { 36 | Map jsonResponse = jsonDecode(response.body); 37 | var data = (jsonResponse['data'] as Map); 38 | return Future.value(data['text']); 39 | } else { 40 | return Future.error( 41 | ErrorResult.create('Error', jsonDecode(response.body))); 42 | } 43 | } 44 | 45 | ///写入设备剪切板 46 | Future writeToDevice(String text) async { 47 | Uri uri = Uri.http(getHost(), '$PATH/write'); 48 | var response = await httpPost(uri, body: {'text': text}); 49 | if (response.statusCode == 200) { 50 | return Future.value(); 51 | } else { 52 | return Future.error( 53 | ErrorResult.create('Error', jsonDecode(response.body))); 54 | } 55 | } 56 | 57 | @override 58 | void dispose() {} 59 | } 60 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/model/photo_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class Album { 16 | Album({ 17 | this.id, 18 | this.name, 19 | this.assetCount, 20 | this.albumType, 21 | }); 22 | 23 | String id; 24 | String name; 25 | int assetCount; 26 | int albumType; 27 | 28 | factory Album.fromJson(Map json) => Album( 29 | id: json["id"], 30 | name: json["name"], 31 | assetCount: json["assetCount"], 32 | albumType: json["albumType"], 33 | ); 34 | 35 | Map toJson() => { 36 | "id": id, 37 | "name": name, 38 | "assetCount": assetCount, 39 | "albumType": albumType, 40 | }; 41 | } 42 | 43 | 44 | class Asset { 45 | Asset({ 46 | this.id, 47 | this.title, 48 | this.type, 49 | this.duration, 50 | this.width, 51 | this.height, 52 | this.createTs, 53 | }); 54 | 55 | String id; 56 | String title; 57 | int type; 58 | int duration; 59 | int width; 60 | int height; 61 | int createTs; 62 | 63 | factory Asset.fromJson(Map json) => Asset( 64 | id: json["id"], 65 | title: json["title"], 66 | type: json["type"], 67 | duration: json["duration"], 68 | width: json["width"], 69 | height: json["height"], 70 | createTs: json["createTs"], 71 | ); 72 | 73 | Map toJson() => { 74 | "id": id, 75 | "title": title, 76 | "type": type, 77 | "duration": duration, 78 | "width": width, 79 | "height": height, 80 | "createTs": createTs, 81 | }; 82 | } -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handlers/app_info_handler.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | 17 | import 'package:k_debug_tools/src/model/base_model.dart'; 18 | import 'package:package_info/package_info.dart'; 19 | import 'package:shelf/shelf.dart'; 20 | import 'package:shelf_router/shelf_router.dart' as shelf; 21 | 22 | import '../handler_def.dart'; 23 | 24 | ///应用信息 25 | class AppInfoHandler extends AbsAppHandler { 26 | @override 27 | shelf.Router get router { 28 | final router = shelf.Router(); 29 | router.get('/info', _info); 30 | return router; 31 | } 32 | 33 | Future _info(Request request) async { 34 | Map data = Map(); 35 | PackageInfo packageInfo = await PackageInfo.fromPlatform(); 36 | data['appName'] = packageInfo.appName; 37 | data['package'] = packageInfo.packageName; 38 | data['version'] = packageInfo.version; 39 | data['buildNumber'] = packageInfo.buildNumber; 40 | List kvs = List(); 41 | data['extra'] = kvs; 42 | 43 | kvs.add(BaseKeyValue( 44 | 'buildTime', 45 | const String.fromEnvironment('BUILD_TIME'), 46 | )); 47 | 48 | kvs.add(BaseKeyValue( 49 | 'gitBranch', 50 | const String.fromEnvironment('GIT_BRANCH'), 51 | )); 52 | 53 | kvs.add(BaseKeyValue( 54 | 'gitCommit', 55 | const String.fromEnvironment('GIT_COMMIT'), 56 | )); 57 | 58 | kvs.add(BaseKeyValue( 59 | 'jenkinsBuildId', 60 | const String.fromEnvironment('JENKINS_BUILD_ID'), 61 | )); 62 | 63 | return ok(data); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/texteditor/text_editor_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 18 | import 'package:k_debug_tools_web/src/web_http.dart'; 19 | 20 | import '../model.dart'; 21 | 22 | class TextEditorBloc extends AppBlocBase { 23 | //路径和文件api一样 24 | static const String PATH = 'api/file'; 25 | 26 | //文本文件路径 27 | final String filePath; 28 | 29 | TextEditorBloc(context, this.filePath) : super(context); 30 | 31 | @override 32 | void dispose() {} 33 | 34 | bool get hasFilePath => filePath?.isNotEmpty == true; 35 | 36 | ///读取文件 37 | Future read() async { 38 | if (!hasFilePath) { 39 | return Future.error('no file path specified'); 40 | } else { 41 | Uri uri = Uri.http(getHost(), '$PATH/read$filePath'); 42 | var response = await httpGet(uri); 43 | if (response.statusCode == 200) { 44 | return Future.value(response.body); 45 | } else { 46 | return Future.error( 47 | ErrorResult.create('Error', jsonDecode(response.body))); 48 | } 49 | } 50 | } 51 | 52 | ///保存 53 | Future save(String text) async { 54 | var queryParameters = { 55 | 'path': Uri.encodeFull(filePath), 56 | }; 57 | Uri uri = Uri.http(getHost(), '$PATH/save', queryParameters); 58 | var response = await httpPost(uri, body: text); 59 | if (response.statusCode == 200) { 60 | return Future.value(); 61 | } else { 62 | return Future.error( 63 | ErrorResult.create('Error', jsonDecode(response.body))); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/photomanager/photo_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class Album { 16 | Album({ 17 | this.id, 18 | this.name, 19 | this.assetCount, 20 | this.albumType, 21 | }); 22 | 23 | String id; 24 | String name; 25 | int assetCount; 26 | int albumType; 27 | 28 | factory Album.fromJson(Map json) => Album( 29 | id: json["id"], 30 | name: json["name"], 31 | assetCount: json["assetCount"], 32 | albumType: json["albumType"], 33 | ); 34 | 35 | Map toJson() => { 36 | "id": id, 37 | "name": name, 38 | "assetCount": assetCount, 39 | "albumType": albumType, 40 | }; 41 | } 42 | 43 | class Asset { 44 | Asset({ 45 | this.id, 46 | this.title, 47 | this.type, 48 | this.duration, 49 | this.width, 50 | this.height, 51 | this.createTs, 52 | }); 53 | 54 | String id; 55 | String title; 56 | int type; 57 | int duration; 58 | int width; 59 | int height; 60 | int createTs; 61 | 62 | factory Asset.fromJson(Map json) => Asset( 63 | id: json["id"], 64 | title: json["title"], 65 | type: json["type"], 66 | duration: json["duration"], 67 | width: json["width"], 68 | height: json["height"], 69 | createTs: json["createTs"], 70 | ); 71 | 72 | Map toJson() => { 73 | "id": id, 74 | "title": title, 75 | "type": type, 76 | "duration": duration, 77 | "width": width, 78 | "height": height, 79 | "createTs": createTs, 80 | }; 81 | } 82 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handler_def.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | 17 | import 'package:flutter/widgets.dart'; 18 | import 'package:shelf/shelf.dart'; 19 | import 'package:shelf_router/shelf_router.dart' as shelf; 20 | 21 | abstract class AbsAppHandler { 22 | shelf.Router get router; 23 | 24 | static Map headers() { 25 | Map headers = Map(); 26 | //允许跨域 27 | headers['Access-Control-Allow-Origin'] = '*'; 28 | headers['Access-Control-Allow-Headers'] = "Token, Pin, Content-Type"; 29 | headers['Content-Type'] = 'application/json; charset=utf-8'; 30 | return headers; 31 | } 32 | 33 | Response notFound({String msg}) { 34 | return Response.notFound( 35 | buildResponseBody(null, message: msg ?? 'Not Found', code: 404), 36 | headers: headers()); 37 | } 38 | 39 | Response error(String error) { 40 | return Response.internalServerError( 41 | body: buildResponseBody(null, message: error, code: 500), 42 | headers: headers()); 43 | } 44 | 45 | Response ok([Object data]) { 46 | return Response.ok(buildResponseBody(data), headers: headers()); 47 | } 48 | 49 | static String buildResponseBody(Object data, {String message, int code}) { 50 | Map resp = Map(); 51 | resp['data'] = data; 52 | resp['message'] = message ?? 'success'; 53 | resp['code'] = code ?? 200; 54 | String str; 55 | try { 56 | str = jsonEncode(resp); 57 | } catch (e, s) { 58 | debugPrint('encode error, $e $s'); 59 | throw e; 60 | } 61 | return str; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tools_web/lib/l10n/app_zh.arb: -------------------------------------------------------------------------------- 1 | { 2 | "requestError": "请求错误: {error}", 3 | "@requestError": { 4 | "placeholders": { 5 | "error": {} 6 | } 7 | }, 8 | "clipboard": "设备剪切板", 9 | "fileExplorer": "文件管理", 10 | "photoManager": "照片管理", 11 | "httpRequest": "网络请求", 12 | "logViewer": "日志查看", 13 | "dbViewer": "数据库管理", 14 | "flutterWidgets": "FlutterWidgets", 15 | "screenCast": "投屏录屏", 16 | "pageNavigator": "路由跳转", 17 | "appInfo": "应用信息", 18 | "deviceInfo": "设备信息", 19 | "readClipboard": "读取剪切板", 20 | "writeClipboard": "写入剪切板", 21 | "display": "屏幕信息", 22 | "hardware": "硬件信息", 23 | "others": "其他信息", 24 | "disconnect": "未连接", 25 | "refresh": "刷新", 26 | "newQuery": "新建查询", 27 | "fileName": "名称", 28 | "fileSize": "大小", 29 | "fileModifyTime": "修改时间", 30 | "back": "返回", 31 | "download": "下载", 32 | "upload": "上传", 33 | "rename": "重命名", 34 | "delete": "删除", 35 | "confirm": "确定", 36 | "cancel": "取消", 37 | "ok": "确定", 38 | "success": "成功", 39 | "save": "保存", 40 | "deleteSelectedFiles": "是否删除选中文件?", 41 | "deleteSuccess": "删除成功", 42 | "addRule": "新建规则", 43 | "editRule": "修改规则", 44 | "allHost": "所有域名", 45 | "filter": "过滤", 46 | "deleteSelectedItems": "是否删除选中数据", 47 | "confirmPopPage": "是否Pop页面\n{pageName}", 48 | "@confirmPopPage": { 49 | "placeholders": { 50 | "pageName": {} 51 | } 52 | }, 53 | "recordFile": "录屏文件", 54 | "recording": "录制中", 55 | "stopRecord": "停止录屏 保存文件: ${file}", 56 | "@stopRecord": { 57 | "placeholders": { 58 | "file": {} 59 | } 60 | }, 61 | "stopFailed": "停止失败", 62 | "startRecord": "开始录屏", 63 | "startFailed": "开启失败", 64 | "checkScreenPermission": "请在手机上授权录屏", 65 | "throttleConfig": "限速配置", 66 | "loadFailed": "加载失败: {error}", 67 | "@loadFailed": { 68 | "placeholders": { 69 | "error": {} 70 | } 71 | }, 72 | "preview": "预览", 73 | "title": "标题", 74 | "wxh": "宽高", 75 | "duration": "时长", 76 | "createTime": "创建时间", 77 | "sort": "排序", 78 | "switchView": "切换视图", 79 | "viewInfo": "查看信息", 80 | "deleteCurrent": "删除当前文件", 81 | "copyLink": "复制链接", 82 | "copied": "已复制" 83 | } -------------------------------------------------------------------------------- /tools_web/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | KDebugTools 18 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 43 | 44 | 45 | 46 | 49 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/photomanager/asset_preview_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'dart:html' as html; 18 | import 'dart:math'; 19 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 20 | import 'package:k_debug_tools_web/src/web_http.dart'; 21 | 22 | import '../model.dart'; 23 | import 'photo_models.dart'; 24 | 25 | class AssetPreviewBloc extends AppBlocBase { 26 | static const String PATH = 'api/photo'; 27 | 28 | AssetPreviewBloc(context) : super(context); 29 | 30 | @override 31 | void dispose() {} 32 | 33 | String networkPath(Asset asset) { 34 | return '${getHostWithSchema()}/$PATH/read?assetId=${asset.id}'; 35 | } 36 | 37 | String networkPathWithToken(Asset asset) { 38 | return '${getHostWithSchema()}/$PATH/read?assetId=${asset.id}&Token=${getToken()}'; 39 | } 40 | 41 | ///下载 42 | Future download(Asset asset) { 43 | var queryParameters = { 44 | 'assetIds': Uri.encodeFull(asset.id), 45 | 'Token': getToken() 46 | }; 47 | Uri uri = Uri.http(getHost(), '$PATH/download', queryParameters); 48 | html.AnchorElement anchorElement = 49 | new html.AnchorElement(href: uri.toString()); 50 | anchorElement.download = uri.toString(); 51 | anchorElement.click(); 52 | return Future.value(); 53 | } 54 | 55 | ///删除 56 | Future delete(Asset asset) async { 57 | Uri uri = Uri.http(getHost(), '$PATH/delete'); 58 | var response = await httpPost(uri, body: { 59 | 'assetIds': [asset.id] 60 | }); 61 | if (response.statusCode == 200) { 62 | Map jsonResponse = jsonDecode(response.body); 63 | List list = (jsonResponse['data'] as Map)['files'] as List; 64 | return list; 65 | } else { 66 | return Future.error( 67 | ErrorResult.create('Error', jsonDecode(response.body))); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/imagepreview/image_preview_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'dart:html' as html; 18 | import 'dart:math'; 19 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 20 | import 'package:k_debug_tools_web/src/web_http.dart'; 21 | 22 | import '../model.dart'; 23 | 24 | class ImagePreviewBloc extends AppBlocBase { 25 | //路径和文件api一样 26 | static const String PATH = 'api/file'; 27 | 28 | //文本文件路径 29 | final String filePath; 30 | 31 | bool _deleted = false; 32 | String _random = ''; 33 | 34 | String get networkPath => 35 | '${getHostWithSchema()}/$PATH/read$filePath?r=$_random&Token=${getToken()}'; 36 | 37 | bool get canDownload => !_deleted && filePath != null; 38 | 39 | ImagePreviewBloc(context, this.filePath) : super(context); 40 | 41 | @override 42 | void dispose() {} 43 | 44 | bool get hasFilePath => filePath?.isNotEmpty == true; 45 | 46 | ///随机加入参数 刷新图片 47 | void refresh() { 48 | _random = Random.secure().nextDouble().toString(); 49 | } 50 | 51 | ///下载 52 | Future download() { 53 | var queryParameters = {'path': Uri.encodeFull(filePath), 'Token': getToken()}; 54 | Uri uri = Uri.http(getHost(), '$PATH/download', queryParameters); 55 | html.AnchorElement anchorElement = 56 | new html.AnchorElement(href: uri.toString()); 57 | anchorElement.download = uri.toString(); 58 | anchorElement.click(); 59 | return Future.value(); 60 | } 61 | 62 | ///删除 63 | Future delete() async { 64 | Uri uri = Uri.http(getHost(), '$PATH/delete'); 65 | var response = await httpPost(uri, body: { 66 | 'path': filePath, 67 | }); 68 | if (response.statusCode == 200) { 69 | _deleted = true; 70 | return Future.value(); 71 | } else { 72 | return Future.error( 73 | ErrorResult.create('Error', jsonDecode(response.body))); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tools_plugin/android/src/main/kotlin/com/kwai/flutter/debugtools/DebugtoolsPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.kwai.flutter.debugtools 2 | 3 | import androidx.annotation.NonNull; 4 | 5 | import io.flutter.embedding.engine.plugins.FlutterPlugin 6 | import io.flutter.plugin.common.MethodCall 7 | import io.flutter.plugin.common.MethodChannel 8 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler 9 | import io.flutter.plugin.common.MethodChannel.Result 10 | import io.flutter.plugin.common.PluginRegistry.Registrar 11 | 12 | /** DebugtoolsPlugin */ 13 | public class DebugtoolsPlugin: FlutterPlugin, MethodCallHandler { 14 | /// The MethodChannel that will the communication between Flutter and native Android 15 | /// 16 | /// This local reference serves to register the plugin with the Flutter Engine and unregister it 17 | /// when the Flutter Engine is detached from the Activity 18 | private lateinit var channel : MethodChannel 19 | 20 | override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { 21 | channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "debugtools") 22 | channel.setMethodCallHandler(this); 23 | } 24 | 25 | // This static function is optional and equivalent to onAttachedToEngine. It supports the old 26 | // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting 27 | // plugin registration via this function while apps migrate to use the new Android APIs 28 | // post-flutter-1.12 via https://flutter.dev/go/android-project-migration. 29 | // 30 | // It is encouraged to share logic between onAttachedToEngine and registerWith to keep 31 | // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called 32 | // depending on the user's project. onAttachedToEngine or registerWith must both be defined 33 | // in the same class. 34 | companion object { 35 | @JvmStatic 36 | fun registerWith(registrar: Registrar) { 37 | val channel = MethodChannel(registrar.messenger(), "debugtools") 38 | channel.setMethodCallHandler(DebugtoolsPlugin()) 39 | } 40 | } 41 | 42 | override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { 43 | if (call.method == "getPlatformVersion") { 44 | result.success("Android ${android.os.Build.VERSION.RELEASE}") 45 | } else { 46 | result.notImplemented() 47 | } 48 | } 49 | 50 | override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { 51 | channel.setMethodCallHandler(null) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /tools_web/lib/src/bloc_provider.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/widgets.dart'; 16 | import 'package:k_debug_tools_web/src/web_bloc.dart'; 17 | 18 | abstract class BlocBase { 19 | @protected 20 | void dispose(); 21 | } 22 | 23 | abstract class AppBlocBase extends BlocBase { 24 | BuildContext context; 25 | 26 | AppBlocBase(this.context); 27 | 28 | String getHost() { 29 | return WebBloc.getHost(); 30 | } 31 | 32 | String getHostWithSchema() { 33 | return WebBloc.getHostWithSchema(); 34 | } 35 | } 36 | 37 | class BlocProvider extends StatefulWidget { 38 | BlocProvider({ 39 | Key key, 40 | @required this.child, 41 | @required this.blocs, 42 | }) : super(key: key); 43 | 44 | final Widget child; 45 | final List blocs; 46 | 47 | @override 48 | _BlocProviderState createState() => _BlocProviderState(); 49 | 50 | static List of(BuildContext context) { 51 | _BlocProviderInherited _provider = 52 | context.getElementForInheritedWidgetOfExactType<_BlocProviderInherited>()?.widget; 53 | return _provider?.blocs; 54 | } 55 | } 56 | 57 | class _BlocProviderState extends State> { 58 | @override 59 | Widget build(BuildContext context) { 60 | return _BlocProviderInherited( 61 | blocs: widget.blocs, 62 | child: widget.child, 63 | ); 64 | } 65 | 66 | @override 67 | void dispose() { 68 | widget.blocs.map((bloc) { 69 | bloc.dispose(); 70 | }); 71 | super.dispose(); 72 | } 73 | } 74 | 75 | class _BlocProviderInherited extends InheritedWidget { 76 | _BlocProviderInherited({ 77 | Key key, 78 | @required Widget child, 79 | @required this.blocs, 80 | }) : super(key: key, child: child); 81 | 82 | final List blocs; 83 | 84 | @override 85 | bool updateShouldNotify(_BlocProviderInherited oldWidget) => false; 86 | } 87 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/navigator/navigator_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class NavigatorInfo { 16 | NavigatorInfo({ 17 | this.name, 18 | this.routes, 19 | }); 20 | 21 | String name; 22 | List routes; 23 | 24 | factory NavigatorInfo.fromJson(Map json) => NavigatorInfo( 25 | name: json["name"], 26 | routes: List.from( 27 | json["routes"].map((x) => RouteInfo.fromJson(x))), 28 | ); 29 | 30 | Map toJson() => { 31 | "name": name, 32 | "routes": List.from(routes.map((x) => x.toJson())), 33 | }; 34 | } 35 | 36 | class RouteInfo { 37 | RouteInfo({ 38 | this.name, 39 | this.settings, 40 | this.top, 41 | this.left, 42 | this.width, 43 | this.height, 44 | this.isCurrent, 45 | this.childNavigators, 46 | }); 47 | 48 | String name; 49 | String settings; 50 | double top; 51 | double left; 52 | double width; 53 | double height; 54 | bool isCurrent; 55 | List childNavigators; 56 | 57 | factory RouteInfo.fromJson(Map json) => RouteInfo( 58 | name: json["name"], 59 | settings: json["settings"], 60 | top: json["top"].toDouble(), 61 | left: json["left"].toDouble(), 62 | width: json["width"].toDouble(), 63 | height: json["height"].toDouble(), 64 | isCurrent: json["isCurrent"], 65 | childNavigators: List.from( 66 | json["childNavigators"].map((x) => NavigatorInfo.fromJson(x))), 67 | ); 68 | 69 | Map toJson() => { 70 | "name": name, 71 | "settings": settings, 72 | "top": top, 73 | "left": left, 74 | "width": width, 75 | "height": height, 76 | "isCurrent": isCurrent, 77 | "childNavigators": 78 | List.from(childNavigators.map((x) => x.toJson())), 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/pagenavigator/page_navigator_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class NavigatorInfo { 16 | NavigatorInfo({ 17 | this.name, 18 | this.routes, 19 | }); 20 | 21 | String name; 22 | List routes; 23 | 24 | factory NavigatorInfo.fromJson(Map json) => NavigatorInfo( 25 | name: json["name"], 26 | routes: List.from( 27 | json["routes"].map((x) => RouteInfo.fromJson(x))), 28 | ); 29 | 30 | Map toJson() => { 31 | "name": name, 32 | "routes": List.from(routes.map((x) => x.toJson())), 33 | }; 34 | } 35 | 36 | class RouteInfo { 37 | RouteInfo({ 38 | this.name, 39 | this.settings, 40 | this.top, 41 | this.left, 42 | this.width, 43 | this.height, 44 | this.isCurrent, 45 | this.childNavigators, 46 | }); 47 | 48 | String name; 49 | String settings; 50 | double top; 51 | double left; 52 | double width; 53 | double height; 54 | bool isCurrent; 55 | List childNavigators; 56 | 57 | factory RouteInfo.fromJson(Map json) => RouteInfo( 58 | name: json["name"], 59 | settings: json["settings"], 60 | top: json["top"].toDouble(), 61 | left: json["left"].toDouble(), 62 | width: json["width"].toDouble(), 63 | height: json["height"].toDouble(), 64 | isCurrent: json["isCurrent"], 65 | childNavigators: List.from( 66 | json["childNavigators"].map((x) => NavigatorInfo.fromJson(x))), 67 | ); 68 | 69 | Map toJson() => { 70 | "name": name, 71 | "settings": settings, 72 | "top": top, 73 | "left": left, 74 | "width": width, 75 | "height": height, 76 | "isCurrent": isCurrent, 77 | "childNavigators": 78 | List.from(childNavigators.map((x) => x.toJson())), 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /tools_web/lib/l10n/app_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "requestError": "Request error: {error}", 3 | "@requestError": { 4 | "placeholders": { 5 | "error": {} 6 | } 7 | }, 8 | "clipboard": "Clipboard", 9 | "fileExplorer": "FileExplorer", 10 | "photoManager": "Photo", 11 | "httpRequest": "HttpRequest", 12 | "logViewer": "LogViewer", 13 | "dbViewer": "DbViewer", 14 | "flutterWidgets": "FlutterWidgets", 15 | "screenCast": "ScreenCast", 16 | "pageNavigator": "PageNavigator", 17 | "appInfo": "AppInfo", 18 | "deviceInfo": "DeviceInfo", 19 | "readClipboard": "Load", 20 | "writeClipboard": "Write", 21 | "display": "Display", 22 | "hardware": "Hardware", 23 | "others": "Others", 24 | "disconnect": "disconnect", 25 | "refresh": "Refresh", 26 | "newQuery": "New Query", 27 | "fileName": "Name", 28 | "fileSize": "Size", 29 | "fileModifyTime": "Last Modified", 30 | "back": "Back", 31 | "download": "Download", 32 | "upload": "Upload", 33 | "rename": "Rename", 34 | "delete": "Delete", 35 | "confirm": "Confirm", 36 | "cancel": "Cancel", 37 | "ok": "Ok", 38 | "success": "Success", 39 | "save": "Save", 40 | "deleteSelectedFiles": "Delete selected files?", 41 | "deleteSuccess": "Delete success", 42 | "addRule": "Add rule", 43 | "editRule": "Edit rule", 44 | "allHost": "Hosts", 45 | "filter": "Filter", 46 | "deleteSelectedItems": "Delete selected items?", 47 | "confirmPopPage": "Pop page\n{pageName}", 48 | "@confirmPopPage": { 49 | "placeholders": { 50 | "pageName": {} 51 | } 52 | }, 53 | "recordFile": "Record files", 54 | "recording": "Recording", 55 | "stopRecord": "Stop recording, path: ${file}", 56 | "@stopRecord": { 57 | "placeholders": { 58 | "file": {} 59 | } 60 | }, 61 | "stopFailed": "Stop failed", 62 | "startRecord": "Start record", 63 | "startFailed": "Start failed", 64 | "checkScreenPermission": "grant permission in device", 65 | "throttleConfig": "ThrottleConfig", 66 | "loadFailed": "Load failed: {error}", 67 | "@loadFailed": { 68 | "placeholders": { 69 | "error": {} 70 | } 71 | }, 72 | "preview": "Preview", 73 | "title": "Title", 74 | "wxh": "WidthHeight", 75 | "duration": "Duration", 76 | "createTime": "Created", 77 | "sort": "Sort", 78 | "switchView": "Switch view", 79 | "viewInfo": "View info", 80 | "deleteCurrent": "delete current", 81 | "copyLink": "Copy link", 82 | "copied": "Copied" 83 | } -------------------------------------------------------------------------------- /tools_web/lib/src/widgets/toast.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:oktoast/oktoast.dart' as ok; 17 | 18 | class KIToast { 19 | /// 20 | /// top 21 | /// bottom 22 | /// center 23 | /// 24 | static void showToast(String content, 25 | {BuildContext context, 26 | ok.ToastPosition position, 27 | bool dismissOtherToast = true, 28 | Duration duration}) { 29 | //position = ToastPosition.top; 30 | position = ok.ToastPosition(align: Alignment.center); 31 | ok.showToast(content, 32 | context: context, 33 | position: position, 34 | duration: duration, 35 | backgroundColor: Color(0xb2000000), 36 | radius: 4, 37 | textPadding: EdgeInsets.only(left: 16, right: 16, top: 11, bottom: 11), 38 | textStyle: TextStyle(fontSize: 14, color: Colors.white), 39 | dismissOtherToast: dismissOtherToast); 40 | } 41 | 42 | static void showToastWidget(Widget widget, {ok.ToastPosition position}) { 43 | showToastWidget(widget, position: position); 44 | } 45 | 46 | static void disMissToast() { 47 | ok.dismissAllToast(); 48 | } 49 | 50 | static Widget buildKToast( 51 | String msg, { 52 | BuildContext context, 53 | TextStyle textStyle = const TextStyle(fontSize: 16, color: Colors.white), 54 | EdgeInsetsGeometry textPadding = 55 | const EdgeInsets.only(left: 20, right: 20, top: 17, bottom: 17), 56 | Color backgroundColor = const Color(0xb2000000), 57 | double radius = 8, 58 | TextAlign textAlign, 59 | }) { 60 | return Container( 61 | margin: const EdgeInsets.all(50.0), 62 | decoration: BoxDecoration( 63 | color: backgroundColor, 64 | borderRadius: BorderRadius.circular(radius), 65 | ), 66 | padding: textPadding, 67 | child: ClipRect( 68 | child: Text( 69 | msg, 70 | style: textStyle, 71 | textAlign: textAlign, 72 | textDirection: TextDirection.ltr, 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/widgets/toast.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:oktoast/oktoast.dart' as ok; 17 | 18 | class Toast { 19 | /// 20 | /// top 21 | /// bottom 22 | /// center 23 | /// 24 | static void showToast(String content, 25 | {BuildContext context, 26 | ok.ToastPosition position, 27 | bool dismissOtherToast = true, 28 | Duration duration}) { 29 | //position = ToastPosition.top; 30 | position = ok.ToastPosition(align: Alignment.topCenter, offset: 265); 31 | ok.showToast(content, 32 | context: context, 33 | position: position, 34 | duration: duration, 35 | backgroundColor: Color(0xb2000000), 36 | radius: 4, 37 | textPadding: EdgeInsets.only(left: 16, right: 16, top: 11, bottom: 11), 38 | textStyle: TextStyle(fontSize: 14, color: Colors.white), 39 | dismissOtherToast: dismissOtherToast); 40 | } 41 | 42 | static void showToastWidget(Widget widget, {ok.ToastPosition position}) { 43 | showToastWidget(widget, position: position); 44 | } 45 | 46 | static void disMissToast() { 47 | ok.dismissAllToast(); 48 | } 49 | 50 | static Widget buildKToast( 51 | String msg, { 52 | BuildContext context, 53 | TextStyle textStyle = const TextStyle(fontSize: 16, color: Colors.white), 54 | EdgeInsetsGeometry textPadding = 55 | const EdgeInsets.only(left: 20, right: 20, top: 17, bottom: 17), 56 | Color backgroundColor = const Color(0xb2000000), 57 | double radius = 8, 58 | TextAlign textAlign, 59 | }) { 60 | return Container( 61 | margin: const EdgeInsets.all(50.0), 62 | decoration: BoxDecoration( 63 | color: backgroundColor, 64 | borderRadius: BorderRadius.circular(radius), 65 | ), 66 | padding: textPadding, 67 | child: ClipRect( 68 | child: Text( 69 | msg, 70 | style: textStyle, 71 | textAlign: textAlign, 72 | textDirection: TextDirection.ltr, 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/logwatcher/log_watcher_controller.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/cupertino.dart'; 16 | import 'package:flutter/foundation.dart'; 17 | import 'package:k_debug_tools/src/webserver/handlers/ws_handler.dart'; 18 | 19 | import 'log_models.dart'; 20 | 21 | ///日志显示 22 | class LogWatcherController { 23 | LogWatcherController._privateConstructor(); 24 | 25 | static final LogWatcherController instance = 26 | LogWatcherController._privateConstructor(); 27 | 28 | DebugPrintCallback _originalDebugPrint; 29 | 30 | ///默认不打开 31 | bool _enable = false; 32 | 33 | bool get enable => _enable; 34 | 35 | ///设置 36 | set enable(n) { 37 | if (_enable != n) { 38 | _enable = n; 39 | _update(); 40 | } 41 | } 42 | 43 | void _update() { 44 | _updatePrint(); 45 | _updateDebugPrint(); 46 | } 47 | 48 | void _updatePrint() {} 49 | 50 | void _updateDebugPrint() { 51 | if (enable) { 52 | _originalDebugPrint = debugPrint; 53 | debugPrint = (String message, {int wrapWidth}) { 54 | _sendToWeb(message, wrapWidth: wrapWidth); 55 | 56 | //send to original 57 | if (_originalDebugPrint != null) { 58 | _originalDebugPrint(message, wrapWidth: wrapWidth); 59 | } 60 | }; 61 | } else { 62 | debugPrint = _originalDebugPrint; 63 | _originalDebugPrint = null; 64 | } 65 | } 66 | 67 | void _sendToWeb(String message, {int wrapWidth}) { 68 | //注意这里面不能再调用 debugPrint 69 | LogEntry logEntry = LogEntry(); 70 | logEntry.level = LogLevel.debug.index; 71 | logEntry.msg = message; 72 | logEntry.time = DateTime.now().millisecondsSinceEpoch; 73 | WebSocketHandler.broadcastJson('logwatcher', 1, logEntry); 74 | } 75 | 76 | ///会发送给web 并且本地debugPrint 77 | void customDebugPrint(String message) { 78 | if (enable) { 79 | _sendToWeb(message); 80 | //send to original 81 | if (_originalDebugPrint != null) { 82 | _originalDebugPrint(message); 83 | } 84 | } else { 85 | debugPrint(message); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /docs/INTEGRATION.md: -------------------------------------------------------------------------------- 1 | # KDebugTools接入手册 2 | 3 | 4 | ## 添加依赖与初始化 5 | 6 | ### 在pubspec.yaml中加入依赖 7 | 8 | ```yaml 9 | ... 10 | dependencies: 11 | ... 12 | k_debug_tools: ^1.0.0 13 | ... 14 | ... 15 | ``` 16 | 17 | ### 初始化 18 | 19 | 参考 [example](../tools_plugin/example/lib/main.dart) 20 | 21 | 导入 `package:k_debug_tools/k_debug_tools.dart`. 22 | 23 | ```dart 24 | ... 25 | Debugger.instance.init( 26 | autoStartWebServer: true, 27 | autoStartHttpHook: true); 28 | ... 29 | ``` 30 | 31 | 32 | ### 在合适的地方加入唤起入口浮窗代码 33 | 34 | ```dart 35 | Debugger.instance.showDebugger(context) 36 | ``` 37 | 38 | ## 本地化配置 39 | 40 | ```dart 41 | setLocalizationOptions(LocalizationOptions.buildEnOptions()) 42 | ``` 43 | or 44 | ```dart 45 | setLocalizationOptions(LocalizationOptions.buildZhOptions()) 46 | ``` 47 | 48 | ## App构建信息 49 | 50 | 工具默认会读取变量变量*BUILD_TIME*、*GIT_BRANCH*、*GIT_COMMIT*、*JENKINS_BUILD_ID* 51 | 52 | 在构建时可通过以下两种方式写入参数(需要flutter版本在1.17.4以上): 53 | 54 | ### 使用flutter命令构建时可使用\--dart-define=KEY=VALUE添加 55 | 56 | ``` 57 | flutter run --dart-define=GIT_BRANCH="$(git rev-parse --abbrev-ref HEAD)" --dart-define=GIT_COMMIT=$(git rev-parse --short HEAD) --dart-define=BUILD_TIME="$(date "+%Y-%m-%d %H:%M:%S")" 58 | ``` 59 | ### 使用gradle构建时使用-Pdart-defines进行添加 60 | 61 | ``` 62 | gradle -Pdart-defines=GIT_BRANCH="$(git rev-parse \--abbrev-ref HEAD)",GIT_COMMIT="$(git rev-parse \--short HEAD)",BUILD_TIME="$(date "+%Y-%m-%d %H:%M:%S")",JENKINS_BUILD_ID=$BUILD_ID clean assembleDebug 63 | ``` 64 | 65 | ## 支持服务器配置 66 | 67 | 在Debugger.instance.init时传入 68 | * allServEnvKeys 可配置key 69 | * allServConfigs 默认服务器配置 70 | 71 | 参考[example的配置](../tools_plugin/example/lib/demo_serv_config.dart) 72 | 73 | 在创建请求时使用以下方法对域名进行映射 74 | 75 | ``` 76 | ServerEnv.instance.mapHost(onlineHost) 77 | ``` 78 | 79 | 使用以下方法获取当前配置的值 80 | 81 | ``` 82 | ServerEnv.instance.getEnvValue(key) 83 | ``` 84 | 85 | ## 添加自定义组件到面板 86 | 87 | ### 添加普通Item 88 | 89 | 调用以下方法添加到某一类目中 90 | 91 | ``` 92 | Debugger.instance.registerItemToXXX(SimpleToolItemWidget item); 93 | ``` 94 | 95 | ### 添加带开关Item 96 | 97 | ``` 98 | Debugger.instance.registerItemToXXX(ToggleToolItemWidget item); 99 | ``` 100 | 101 | ## Web端文件管理 添加自定义路径, 如下载目录、缓存目录等 102 | 103 | ``` 104 | Debugger.instance.addCustomDirToRoot(String name, String absolute); 105 | ``` 106 | 107 | ## Web端DbView 添加自定义文件 108 | 109 | ``` 110 | Debugger.instance.registerDbFile(String filePath); 111 | ``` 112 | 113 | ## 支持Web端FlutterUI功能 114 | 115 | 在根节点widget上包裹RepaintBoundary 116 | 117 | 参考[example代码](../tools_plugin/example/lib/main.dart) 118 | 119 | 120 | ## 支持相册管理功能 121 | 122 | 若应用未申请权限则需要进行申请 123 | 124 | 125 | 参考[PhotoManager](https://pub.dev/packages/photo_manager#ios-config) -------------------------------------------------------------------------------- /tools_plugin/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: debugtools_example 2 | description: Demonstrates how to use the debugtools plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | k_debug_tools: 16 | # When depending on this package from a real application you should use: 17 | # debugtools: ^x.y.z 18 | # See https://dart.dev/tools/pub/dependencies#version-constraints 19 | # The example app is bundled with the plugin so we use a path dependency on 20 | # the parent directory to use the current plugin's version. 21 | path: ../ 22 | vm_service: 4.1.0 23 | 24 | # The following adds the Cupertino Icons font to your application. 25 | # Use with the CupertinoIcons class for iOS style icons. 26 | cupertino_icons: ^0.1.3 27 | 28 | dev_dependencies: 29 | flutter_test: 30 | sdk: flutter 31 | 32 | # For information on the generic Dart part of this file, see the 33 | # following page: https://dart.dev/tools/pub/pubspec 34 | 35 | # The following section is specific to Flutter. 36 | flutter: 37 | 38 | # The following line ensures that the Material Icons font is 39 | # included with your application, so that you can use the icons in 40 | # the material Icons class. 41 | uses-material-design: true 42 | 43 | # To add assets to your application, add an assets section, like this: 44 | # assets: 45 | # - images/a_dot_burr.jpeg 46 | # - images/a_dot_ham.jpeg 47 | 48 | # An image asset can refer to one or more resolution-specific "variants", see 49 | # https://flutter.dev/assets-and-images/#resolution-aware. 50 | 51 | # For details regarding adding assets from package dependencies, see 52 | # https://flutter.dev/assets-and-images/#from-packages 53 | 54 | # To add custom fonts to your application, add a fonts section here, 55 | # in this "flutter" section. Each entry in this list should have a 56 | # "family" key with the font family name, and a "fonts" key with a 57 | # list giving the asset and other descriptors for the font. For 58 | # example: 59 | # fonts: 60 | # - family: Schyler 61 | # fonts: 62 | # - asset: fonts/Schyler-Regular.ttf 63 | # - asset: fonts/Schyler-Italic.ttf 64 | # style: italic 65 | # - family: Trajan Pro 66 | # fonts: 67 | # - asset: fonts/TrajanPro.ttf 68 | # - asset: fonts/TrajanPro_Bold.ttf 69 | # weight: 700 70 | # 71 | # For details regarding fonts from package dependencies, 72 | # see https://flutter.dev/custom-fonts/#from-packages 73 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/uicheck/uicheck_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'dart:html' as html; 18 | import 'package:k_debug_tools_web/src/app/uicheck/uicheck_models.dart'; 19 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 20 | import 'package:k_debug_tools_web/src/web_http.dart'; 21 | 22 | import '../model.dart'; 23 | 24 | class UiCheckBloc extends AppBlocBase { 25 | static const String PATH = 'api/uicheck'; 26 | 27 | FlutterCapture _flutterCapture; 28 | 29 | Uri get _uri => 30 | Uri.parse('${getHostWithSchema()}/$PATH/${_flutterCapture?.screenshot}'); 31 | 32 | String get screenshotNetPath => _uri.toString(); 33 | 34 | bool get hasScreenshot => (_flutterCapture?.screenshot?.isNotEmpty == true); 35 | 36 | double get deviceHeight => _flutterCapture?.screenHeight ?? 0; 37 | 38 | double get deviceWidth => _flutterCapture?.screenWidth ?? 0; 39 | 40 | double get paddingTop => _flutterCapture?.paddingTop ?? 0; 41 | 42 | double get paddingBottom => _flutterCapture?.paddingBottom ?? 0; 43 | 44 | WidgetNode get root => _flutterCapture?.rootWidget; 45 | 46 | UiCheckBloc(context) : super(context); 47 | 48 | @override 49 | void dispose() {} 50 | 51 | ///抓取 52 | Future capture() async { 53 | _flutterCapture = null; 54 | Uri uri = Uri.http(getHost(), '$PATH/capture'); 55 | var response = await httpPost(uri); 56 | if (response.statusCode == 200) { 57 | //记录时间 58 | Map jsonResponse = jsonDecode(response.body); 59 | var data = (jsonResponse['data'] as Map); 60 | _flutterCapture = FlutterCapture.fromJson(data); 61 | return Future.value(); 62 | } else { 63 | return Future.error( 64 | ErrorResult.create('Error', jsonDecode(response.body))); 65 | } 66 | } 67 | 68 | ///下载图片 69 | Future downloadScreenshot() { 70 | html.AnchorElement anchorElement = 71 | new html.AnchorElement(href: _uri.toString()); 72 | anchorElement.href = _uri.toString(); 73 | anchorElement.download = '${_flutterCapture?.screenshot}'; 74 | anchorElement.click(); 75 | return Future.value(); 76 | } 77 | 78 | Future openScreenshotInNewTab() { 79 | html.window.open(_uri.toString(), '${_flutterCapture?.screenshot}'); 80 | return Future.value(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/photomanager/widgets/asset_item_thumb.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:cached_network_image/cached_network_image.dart'; 16 | import 'package:flutter/foundation.dart'; 17 | import 'package:flutter/material.dart'; 18 | import 'package:flutter/widgets.dart'; 19 | import 'package:k_debug_tools_web/src/app/photomanager/photo_models.dart'; 20 | import 'package:visibility_detector/visibility_detector.dart'; 21 | 22 | import '../../../web_http.dart'; 23 | 24 | class AssetItemThumbWidget extends StatefulWidget { 25 | final Asset asset; 26 | final String thumbUrl; 27 | final bool showVideoIcon; 28 | 29 | const AssetItemThumbWidget( 30 | {Key key, 31 | @required this.asset, 32 | @required this.thumbUrl, 33 | this.showVideoIcon = true}) 34 | : super(key: key); 35 | 36 | @override 37 | _AssetItemThumbWidgetState createState() => _AssetItemThumbWidgetState(); 38 | } 39 | 40 | class _AssetItemThumbWidgetState extends State { 41 | ValueNotifier _showImage = ValueNotifier(false); 42 | bool _hasShown = false; 43 | 44 | @override 45 | Widget build(BuildContext context) { 46 | return VisibilityDetector( 47 | key: Key(widget.thumbUrl), 48 | onVisibilityChanged: (info) { 49 | _showImage.value = _hasShown || info.visibleFraction > 0; 50 | _hasShown = _showImage.value; 51 | }, 52 | child: ValueListenableBuilder( 53 | valueListenable: _showImage, 54 | builder: (ctx, showImage, child) { 55 | return Stack( 56 | fit: StackFit.expand, 57 | children: [ 58 | Visibility( 59 | visible: showImage, 60 | child: CachedNetworkImage( 61 | placeholder: (context, url) => Container(), 62 | imageUrl: widget.thumbUrl, 63 | httpHeaders: {'Token': getToken()}, 64 | imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet, 65 | )), 66 | Positioned( 67 | top: 3, 68 | left: 3, 69 | child: (widget.showVideoIcon && widget.asset.type == 2) 70 | ? Icon(Icons.slideshow_rounded) 71 | : Container()) 72 | ], 73 | ); 74 | }, 75 | )); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/uicheck/uicheck_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class FlutterCapture { 16 | FlutterCapture({ 17 | this.screenWidth, 18 | this.screenHeight, 19 | this.paddingTop, 20 | this.paddingBottom, 21 | this.screenshot, 22 | this.rootWidget, 23 | }); 24 | 25 | double screenWidth; 26 | double screenHeight; 27 | double paddingTop; 28 | double paddingBottom; 29 | String screenshot; 30 | WidgetNode rootWidget; 31 | 32 | factory FlutterCapture.fromJson(Map json) => FlutterCapture( 33 | screenWidth: json["screenWidth"], 34 | screenHeight: json["screenHeight"], 35 | paddingTop: json["paddingTop"], 36 | paddingBottom: json["paddingBottom"], 37 | screenshot: json["screenshot"], 38 | rootWidget: WidgetNode.fromJson(json["rootWidget"]), 39 | ); 40 | 41 | Map toJson() => { 42 | "screenWidth": screenWidth, 43 | "screenHeight": screenHeight, 44 | "paddingTop": paddingTop, 45 | "paddingBottom": paddingBottom, 46 | "screenshot": screenshot, 47 | "rootWidget": rootWidget.toJson(), 48 | }; 49 | } 50 | 51 | class WidgetNode { 52 | WidgetNode({ 53 | this.name, 54 | this.data, 55 | this.width, 56 | this.height, 57 | this.left, 58 | this.top, 59 | this.attrs, 60 | this.children, 61 | }); 62 | 63 | String name; 64 | String data; 65 | double width; 66 | double height; 67 | double left; 68 | double top; 69 | Map attrs; 70 | List children; 71 | 72 | factory WidgetNode.fromJson(Map json) => WidgetNode( 73 | name: json["name"], 74 | data: json["data"], 75 | width: json["width"], 76 | height: json["height"], 77 | left: json["left"], 78 | top: json["top"], 79 | attrs: json["attrs"], 80 | children: json["children"] == null 81 | ? null 82 | : List.from( 83 | json["children"].map((x) => WidgetNode.fromJson(x))), 84 | ); 85 | 86 | Map toJson() => { 87 | "name": name, 88 | "data": data, 89 | "width": width, 90 | "height": height, 91 | "left": left, 92 | "top": top, 93 | "attrs": attrs, 94 | "children": children == null 95 | ? null 96 | : children.map((e) => e.toJson()).toList(growable: false) 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/uicheck/uicheck_models.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | class FlutterCapture { 16 | FlutterCapture({ 17 | this.screenWidth, 18 | this.screenHeight, 19 | this.paddingTop, 20 | this.paddingBottom, 21 | this.screenshot, 22 | this.rootWidget, 23 | }); 24 | 25 | double screenWidth; 26 | double screenHeight; 27 | double paddingTop; 28 | double paddingBottom; 29 | String screenshot; 30 | WidgetNode rootWidget; 31 | 32 | factory FlutterCapture.fromJson(Map json) => FlutterCapture( 33 | screenWidth: json["screenWidth"], 34 | screenHeight: json["screenHeight"], 35 | paddingTop: json["paddingTop"], 36 | paddingBottom: json["paddingBottom"], 37 | screenshot: json["screenshot"], 38 | rootWidget: WidgetNode.fromJson(json["rootWidget"]), 39 | ); 40 | 41 | Map toJson() => { 42 | "screenWidth": screenWidth, 43 | "screenHeight": screenHeight, 44 | "paddingTop": paddingTop, 45 | "paddingBottom": paddingBottom, 46 | "screenshot": screenshot, 47 | "rootWidget": rootWidget.toJson(), 48 | }; 49 | } 50 | 51 | class WidgetNode { 52 | WidgetNode({ 53 | this.name, 54 | this.data, 55 | this.width, 56 | this.height, 57 | this.left, 58 | this.top, 59 | this.attrs, 60 | this.children, 61 | }); 62 | 63 | String name; 64 | String data; 65 | double width; 66 | double height; 67 | double left; 68 | double top; 69 | Map attrs; 70 | List children; 71 | 72 | factory WidgetNode.fromJson(Map json) => WidgetNode( 73 | name: json["name"], 74 | data: json["data"], 75 | width: json["width"], 76 | height: json["height"], 77 | left: json["left"], 78 | top: json["top"], 79 | attrs: json["attrs"], 80 | children: json["children"] == null 81 | ? null 82 | : List.from( 83 | json["children"].map((x) => WidgetNode.fromJson(x))), 84 | ); 85 | 86 | Map toJson() => { 87 | "name": name, 88 | "data": data, 89 | "width": width, 90 | "height": height, 91 | "left": left, 92 | "top": top, 93 | "attrs": attrs, 94 | "children": children == null 95 | ? null 96 | : children.map((e) => e.toJson()).toList(growable: false) 97 | }; 98 | } 99 | -------------------------------------------------------------------------------- /tools_plugin/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 17 | 24 | 28 | 32 | 37 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /tools_plugin/example/lib/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | import 'dart:io'; 17 | 18 | import 'package:flutter/material.dart'; 19 | import 'package:k_debug_tools/k_debug_tools.dart'; 20 | 21 | import 'demo_serv_config.dart'; 22 | 23 | void main() { 24 | WidgetsFlutterBinding.ensureInitialized(); 25 | runApp(MyApp()); 26 | Debugger.instance.init( 27 | autoStartWebServer: true, 28 | autoStartHttpHook: true, 29 | allServEnvKeys: EnvKeys, 30 | allServConfigs: ServerConfigs); 31 | } 32 | 33 | class MyApp extends StatefulWidget { 34 | @override 35 | _MyAppState createState() => _MyAppState(); 36 | } 37 | 38 | class _MyAppState extends State { 39 | @override 40 | void initState() { 41 | super.initState(); 42 | //auto show Debugger icon 43 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) { 44 | Debugger.instance.showDebugger(context); 45 | }); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | //RepaintBoundary用于flutter截图功能 51 | return RepaintBoundary( 52 | child: MaterialApp( 53 | home: Scaffold( 54 | appBar: AppBar( 55 | title: const Text('KDebugTools'), 56 | ), 57 | body: Builder( 58 | builder: (ctx) { 59 | return Column( 60 | mainAxisAlignment: MainAxisAlignment.center, 61 | crossAxisAlignment: CrossAxisAlignment.stretch, 62 | children: [ 63 | FlatButton( 64 | onPressed: () { 65 | Debugger.instance.showDebuggerDialog(ctx); 66 | }, 67 | child: Text('Click >>> ShowDebugger'), 68 | ), 69 | SizedBox( 70 | height: 10, 71 | ), 72 | FlatButton( 73 | onPressed: () { 74 | HttpClient() 75 | .getUrl(Uri.parse('https://www.kuaishou.com/')) 76 | .then((value) async { 77 | var resp = await value.close(); 78 | var responseBody = 79 | await resp.transform(Utf8Decoder()).join(); 80 | }); 81 | }, 82 | child: Text('Click >>> make Http request'), 83 | ), 84 | ], 85 | ); 86 | }, 87 | ), 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/videoplayer/video_player.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:video_player/video_player.dart'; 16 | import 'package:chewie/chewie.dart'; 17 | import 'package:flutter/cupertino.dart'; 18 | import 'package:flutter/material.dart'; 19 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 20 | 21 | import '../../app_window_bloc.dart'; 22 | import 'video_player_bloc.dart'; 23 | 24 | class VideoPlayerWindow extends StatefulWidget { 25 | final String filePath; 26 | 27 | VideoPlayerWindow({Key key, this.filePath}) : super(key: key); 28 | 29 | @override 30 | _VideoPlayerWindowState createState() => _VideoPlayerWindowState(); 31 | } 32 | 33 | class _VideoPlayerWindowState extends State { 34 | VideoPlayerBloc _bloc; 35 | 36 | @override 37 | void dispose() { 38 | _bloc?.dispose(); 39 | super.dispose(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | _bloc ??= VideoPlayerBloc(context, widget.filePath); 45 | return BlocProvider( 46 | child: VideoPlayer(), 47 | blocs: [_bloc], 48 | ); 49 | } 50 | } 51 | 52 | class VideoPlayer extends StatefulWidget { 53 | @override 54 | _VideoPlayerState createState() => _VideoPlayerState(); 55 | } 56 | 57 | class _VideoPlayerState extends State { 58 | AppWindowBloc _windowBloc; 59 | VideoPlayerBloc _playerBloc; 60 | VideoPlayerController _videoPlayerController; 61 | ChewieController _chewieController; 62 | 63 | @override 64 | void initState() { 65 | _windowBloc = BlocProvider.of(context).first; 66 | _playerBloc = BlocProvider.of(context).first; 67 | _videoPlayerController = 68 | VideoPlayerController.network(_playerBloc.networkPath); 69 | _chewieController = ChewieController( 70 | videoPlayerController: _videoPlayerController, 71 | aspectRatio: 1 / 1, 72 | autoPlay: true, 73 | looping: false, 74 | allowFullScreen: false, 75 | customControls: MaterialControls(), 76 | ); 77 | super.initState(); 78 | } 79 | 80 | @override 81 | void dispose() { 82 | _videoPlayerController.dispose(); 83 | _chewieController.dispose(); 84 | super.dispose(); 85 | } 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | return _buildContentWidget(); 90 | } 91 | 92 | Widget _buildContentWidget() { 93 | return SizedBox.expand( 94 | child: Chewie( 95 | controller: _chewieController, 96 | ), 97 | ); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /tools_web/lib/src/widgets/flutter_cursor/flutter_cursor.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/gestures.dart'; 16 | import 'package:flutter/widgets.dart'; 17 | import 'dart:html' as html; 18 | import 'cursors.dart'; 19 | 20 | /// Custom hover cursor on web. 21 | /// Wrap your child with this widget, and when the cursor enters/lease the widget, it will change the browser cursor. 22 | class HoverCursor extends StatefulWidget { 23 | final Widget child; 24 | 25 | /// Cursor to show when entering hover zone. 26 | final Cursor cursor; 27 | 28 | /// Custom custom that is applied when entering hover zone. Overrides [cursor] when set. 29 | /// Can be any CSS `cursor` value, included a URL with x/y. 30 | final String customCursor; 31 | 32 | /// Custom to set when exiting hover zone. Setting to empty/`null` will reset. 33 | final String exitCursor; 34 | 35 | /// Whether to show exit cursor when disposing this widget. 36 | final bool exitOnDispose; 37 | 38 | const HoverCursor({ 39 | Key key, 40 | this.child, 41 | this.cursor, 42 | this.customCursor, 43 | this.exitCursor, 44 | this.exitOnDispose = true, 45 | }) : super(key: key); 46 | 47 | @override 48 | _HoverCursorState createState() => _HoverCursorState(); 49 | } 50 | 51 | class _HoverCursorState extends State { 52 | @override 53 | Widget build(BuildContext context) { 54 | return _HoverCursor( 55 | child: widget.child, 56 | cursor: widget.cursor, 57 | customCursor: widget.customCursor, 58 | exitCursor: widget.exitCursor, 59 | ); 60 | } 61 | 62 | @override 63 | void dispose() { 64 | super.dispose(); 65 | 66 | if (widget.exitOnDispose) { 67 | _HoverCursor.body.style.cursor = widget.exitCursor; 68 | } 69 | } 70 | } 71 | 72 | class _HoverCursor extends MouseRegion { 73 | //add id to body and set cursor of that doesn't work. 74 | // Because flt-glass-pane is replacing the cursor. 75 | // So the solution is that set cursor directly to flt-glass-pane. 76 | // static final body = 77 | // html.window.document.getElementsByTagName('body')[0] as html.Element; 78 | static final body = 79 | html.window.document.querySelectorAll('flt-glass-pane')[0]; 80 | 81 | _HoverCursor({ 82 | Widget child, 83 | Cursor cursor, 84 | String customCursor, 85 | String exitCursor, 86 | }) : super( 87 | onHover: (PointerHoverEvent evt) { 88 | body.style.cursor = customCursor ?? CursorValues[cursor]; 89 | }, 90 | onExit: (PointerExitEvent evt) { 91 | body.style.cursor = exitCursor; 92 | }, 93 | child: child, 94 | ); 95 | } 96 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/http/httparchive/http_request_widget.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | 17 | import 'package:flutter/material.dart'; 18 | 19 | import '../http_models.dart'; 20 | import 'http_archive_list_page.dart'; 21 | 22 | class RequestWidget extends StatefulWidget { 23 | final HttpArchive httpArchive; 24 | 25 | RequestWidget(this.httpArchive); 26 | 27 | @override 28 | _RequestWidgetState createState() => _RequestWidgetState(); 29 | } 30 | 31 | class _RequestWidgetState extends State 32 | with AutomaticKeepAliveClientMixin { 33 | HttpArchive get httpArchive => widget.httpArchive; 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | super.build(context); 38 | int end = httpArchive.end; 39 | var requestTime = 40 | getDateTimeStr(DateTime.fromMillisecondsSinceEpoch(httpArchive.start)); 41 | var responseTime = end != null 42 | ? getDateTimeStr(DateTime.fromMillisecondsSinceEpoch(end)) 43 | : ''; 44 | var duration = end != null ? (end - httpArchive.start) : 0; 45 | var body = HttpArchive.decodeBody(httpArchive.requestBody); 46 | var content = StringBuffer(); 47 | content.write('url: ${httpArchive.url}\n'); 48 | content.write('method: ${httpArchive.method.toUpperCase()}\n'); 49 | content.write('requestTime: $requestTime\n'); 50 | content.write('responseTime: $responseTime\n'); 51 | content.write( 52 | 'remoteAddress: ${httpArchive.requestConnectInfo?.remoteAddress ?? ''}:${httpArchive.requestConnectInfo?.remotePort ?? ''}\n'); 53 | content.write('duration: ${duration}ms\n\n'); 54 | content.write('headers: \n'); 55 | content.write('${toJson(stripValue(httpArchive.requestHeaders))}\n\n'); 56 | content.write('params: \n'); 57 | content 58 | .write('${toJson(stripValue(httpArchive.uri.queryParametersAll))}\n\n'); 59 | content.write('body: \n'); 60 | if (isJsonStr(body)) { 61 | content.write(toJson(jsonDecode(body))); 62 | } else { 63 | content.write(body ?? ''); 64 | } 65 | content.write('\n'); 66 | 67 | return Padding( 68 | padding: const EdgeInsets.all(8.0), 69 | child: Column( 70 | crossAxisAlignment: CrossAxisAlignment.start, 71 | children: [ 72 | RaisedButton( 73 | onPressed: () { 74 | copyClipboard(context, content.toString()); 75 | }, 76 | child: Text('copy all'), 77 | ), 78 | Expanded( 79 | child: Scrollbar( 80 | child: SelectableText(content.toString()), 81 | ), 82 | ), 83 | ], 84 | ), 85 | ); 86 | } 87 | 88 | @override 89 | bool get wantKeepAlive => true; 90 | } 91 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/widgets/progress_dialog.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | 17 | class ProgressDialog extends Dialog { 18 | @override 19 | Widget build(BuildContext context) { 20 | return Material( 21 | type: MaterialType.transparency, 22 | child: LoadingContent(false), 23 | ); 24 | } 25 | } 26 | 27 | class LoadingContent extends StatefulWidget { 28 | final bool _centerOnly; 29 | 30 | LoadingContent(this._centerOnly); 31 | 32 | @override 33 | LoadingState createState() => LoadingState(_centerOnly); 34 | } 35 | 36 | class LoadingState extends State 37 | with SingleTickerProviderStateMixin { 38 | final bool _centerOnly; 39 | 40 | LoadingState(this._centerOnly); 41 | 42 | AnimationController _animationController; 43 | 44 | @override 45 | void initState() { 46 | super.initState(); 47 | _animationController = 48 | AnimationController(vsync: this, duration: Duration(seconds: 1)); 49 | _animationController.repeat(); 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | if (_centerOnly) { 55 | return _center(); 56 | } else { 57 | return Center( 58 | heightFactor: 1, 59 | widthFactor: 1, 60 | child: Container( 61 | width: 100, 62 | height: 100, 63 | decoration: BoxDecoration( 64 | color: Colors.black.withOpacity(0.5), 65 | borderRadius: BorderRadius.circular(10.0)), 66 | child: _center(), 67 | ), 68 | ); 69 | } 70 | } 71 | 72 | Widget _center() { 73 | return Column( 74 | mainAxisAlignment: MainAxisAlignment.center, 75 | mainAxisSize: MainAxisSize.min, 76 | children: [ 77 | RotationTransition( 78 | turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( 79 | parent: _animationController, curve: Curves.linear)), 80 | child: Container( 81 | height: 60.0, 82 | width: 60.0, 83 | child: Icon( 84 | Icons.rotate_right, 85 | size: 36, 86 | color: Colors.white, 87 | )), 88 | ), 89 | ], 90 | ); 91 | } 92 | 93 | @override 94 | void dispose() { 95 | _animationController.dispose(); 96 | super.dispose(); 97 | } 98 | } 99 | 100 | showLoadingDialog(BuildContext context) { 101 | showDialog( 102 | context: context, 103 | builder: (context) => ProgressDialog(), 104 | barrierDismissible: false); 105 | } 106 | 107 | dismissLoadingDialog(BuildContext context) { 108 | Navigator.of(context, rootNavigator: true).pop(context); 109 | } 110 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/photomanager/widgets/album_tree.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:flutter/widgets.dart'; 17 | import 'package:k_debug_tools_web/src/app/photomanager/photo_models.dart'; 18 | import 'package:k_debug_tools_web/src/widgets/tree.dart'; 19 | 20 | import '../../../app_window_bloc.dart'; 21 | import '../../../bloc_provider.dart'; 22 | import '../photo_manager_bloc.dart'; 23 | 24 | ///文件夹树形结构 25 | class AlbumTreeWidget extends StatefulWidget { 26 | @override 27 | _AlbumTreeWidgetState createState() => _AlbumTreeWidgetState(); 28 | } 29 | 30 | class _AlbumTreeWidgetState extends State { 31 | PhotoManagerBloc _photoBloc; 32 | Node _root; 33 | Node _selectedNode; 34 | 35 | @override 36 | void initState() { 37 | _photoBloc = BlocProvider.of(context).first; 38 | super.initState(); 39 | } 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return StreamBuilder( 44 | stream: _photoBloc.photoStream, 45 | builder: (ctx, _) { 46 | _buildRootNode(); 47 | return TreeView( 48 | root: _root, 49 | showRoot: true, 50 | onTap: (n) { 51 | _setSelect(n); 52 | }, 53 | onDoubleTap: (n) { 54 | _setSelect(n); 55 | }, 56 | onExpand: (n) { 57 | n.expanded = !n.expanded; 58 | setState(() {}); 59 | }, 60 | ); 61 | }); 62 | } 63 | 64 | ///设置选中 65 | void _setSelect(Node n) { 66 | if (_selectedNode != n) { 67 | _selectedNode?.selected = false; 68 | _selectedNode = n; 69 | n.selected = true; 70 | //显示相册 71 | _photoBloc.showAlbum(n.data); 72 | setState(() {}); 73 | } 74 | } 75 | 76 | Node _buildRootNode() { 77 | if (_root == null) { 78 | _root = Node(); 79 | _root.key = 'root'; 80 | _root.label = 'Albums'; 81 | _root.expandable = true; 82 | _root.expanded = true; 83 | } 84 | _root.expandable = _photoBloc.albums.isNotEmpty; 85 | //清空旧数据 86 | _root.subs = []; 87 | //创建 88 | _photoBloc.albums.forEach((element) { 89 | _buildAlbumNode(element); 90 | }); 91 | return _root; 92 | } 93 | 94 | void _buildAlbumNode(Album album) { 95 | String key = album.id; 96 | Node node = Node(); 97 | node.key = key; 98 | node.icon = Icons.folder; 99 | node.label = '[${album.assetCount}] ${album.name}'; 100 | node.data = album; 101 | node.expandable = false; 102 | node.selected = _photoBloc.showingAlbum == album; 103 | _root.subs.add(node); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/widgets/floating_button.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:flutter/widgets.dart'; 17 | 18 | import '../debugger.dart'; 19 | 20 | class FloatingButtonWidget extends StatefulWidget { 21 | final Function onTap; 22 | final double btnSize; 23 | final IconData icon; 24 | 25 | FloatingButtonWidget({ 26 | this.onTap, 27 | this.btnSize = 66, 28 | this.icon = Icons.bug_report, 29 | }); 30 | 31 | @override 32 | _FloatingButtonWidgetState createState() => _FloatingButtonWidgetState(); 33 | } 34 | 35 | class _FloatingButtonWidgetState extends State { 36 | double left = 30; 37 | double top = 80; 38 | double screenWidth; 39 | double screenHeight; 40 | double _opacity = 0.5; 41 | 42 | @override 43 | void initState() { 44 | super.initState(); 45 | } 46 | 47 | @override 48 | Widget build(BuildContext context) { 49 | screenWidth = MediaQuery.of(context).size.width; 50 | screenHeight = MediaQuery.of(context).size.height; 51 | 52 | ///默认点击事件 53 | var tap = () { 54 | Debugger.instance.showDebuggerDialog(context); 55 | }; 56 | Widget w; 57 | Color primaryColor = Theme.of(context).primaryColor; 58 | primaryColor = primaryColor.withOpacity(0.6); 59 | w = GestureDetector( 60 | onTap: widget.onTap ?? tap, 61 | onDoubleTap: () { 62 | Debugger.instance.hideDebugger(); 63 | }, 64 | onPanUpdate: _dragUpdate, 65 | onPanEnd: (v) { 66 | _opacity = 0.5; 67 | setState(() {}); 68 | }, 69 | child: Container( 70 | child: Icon( 71 | widget.icon, 72 | size: 44, 73 | color: Colors.black.withOpacity(_opacity), 74 | ), 75 | color: Colors.blueGrey[300].withOpacity(_opacity)), 76 | ); 77 | 78 | ///圆形 79 | w = ClipRRect( 80 | borderRadius: BorderRadius.circular(widget.btnSize / 2), 81 | child: w, 82 | ); 83 | 84 | ///计算偏移量限制 85 | if (left < 1) { 86 | left = 1; 87 | } 88 | if (left > screenWidth - widget.btnSize) { 89 | left = screenWidth - widget.btnSize; 90 | } 91 | 92 | if (top < 1) { 93 | top = 1; 94 | } 95 | if (top > screenHeight - widget.btnSize) { 96 | top = screenHeight - widget.btnSize; 97 | } 98 | w = Container( 99 | alignment: Alignment.topLeft, 100 | margin: EdgeInsets.only(left: left, top: top), 101 | child: w, 102 | ); 103 | return w; 104 | } 105 | 106 | _dragUpdate(DragUpdateDetails detail) { 107 | _opacity = 1; 108 | Offset offset = detail.delta; 109 | left = left + offset.dx; 110 | top = top + offset.dy; 111 | setState(() {}); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/http/httparchive/http_response_widget.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | 17 | import 'package:flutter/material.dart'; 18 | 19 | import '../http_models.dart'; 20 | import 'http_archive_list_page.dart'; 21 | import 'json_view.dart'; 22 | 23 | class ResponseWidget extends StatefulWidget { 24 | final HttpArchive httpArchive; 25 | 26 | ResponseWidget(this.httpArchive); 27 | 28 | @override 29 | _ResponseWidgetState createState() => _ResponseWidgetState(); 30 | } 31 | 32 | class _ResponseWidgetState extends State 33 | with AutomaticKeepAliveClientMixin { 34 | bool isShowAll = false; 35 | double fontSize = 14; 36 | 37 | HttpArchive get httpArchive => widget.httpArchive; 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | super.build(context); 42 | var jsonStr = HttpArchive.decodeBody(widget.httpArchive.responseBody) ?? 43 | '>>>preview not support<<<'; 44 | var isJson = isJsonStr(jsonStr); 45 | 46 | var content = StringBuffer(); 47 | content.write('headers: \n'); 48 | content.write('${toJson(stripValue(httpArchive.responseHeaders))}\n\n'); 49 | if (!isJson) { 50 | content.write(jsonStr ?? ''); 51 | } 52 | 53 | return SingleChildScrollView( 54 | child: Padding( 55 | padding: const EdgeInsets.all(8.0), 56 | child: Column( 57 | crossAxisAlignment: CrossAxisAlignment.stretch, 58 | children: [ 59 | Row( 60 | children: [ 61 | RaisedButton( 62 | onPressed: () { 63 | copyClipboard(context, jsonStr); 64 | }, 65 | child: Text('copy json'), 66 | ), 67 | SizedBox(width: 10), 68 | Text(isShowAll ? 'shrink all' : 'expand all'), 69 | Checkbox( 70 | value: isShowAll, 71 | onChanged: (check) { 72 | isShowAll = check; 73 | setState(() {}); 74 | }, 75 | ), 76 | Expanded( 77 | child: Slider( 78 | value: fontSize, 79 | max: 30, 80 | min: 1, 81 | onChanged: (v) { 82 | fontSize = v; 83 | setState(() {}); 84 | }, 85 | ), 86 | ), 87 | ], 88 | ), 89 | SelectableText( 90 | content.toString(), 91 | style: TextStyle(fontSize: fontSize), 92 | ), 93 | isJson 94 | ? JsonView( 95 | json: jsonDecode(jsonStr), 96 | isShowAll: isShowAll, 97 | fontSize: fontSize, 98 | ) 99 | : Container(), 100 | ], 101 | ), 102 | )); 103 | } 104 | 105 | @override 106 | bool get wantKeepAlive => true; 107 | } 108 | -------------------------------------------------------------------------------- /tools_plugin/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/http/httphook/config_provider.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:path/path.dart'; 16 | import 'package:flutter/cupertino.dart'; 17 | import 'package:sqflite/sqflite.dart'; 18 | 19 | import 'config_models.dart'; 20 | 21 | class ConfigProvider { 22 | static const String _DEFAULT_DB = 'KDebugTools_http_hook.db'; 23 | static const int dbVersion = 1; 24 | 25 | ///表 26 | static const String _DEFAULT_TABLE = 'config'; 27 | 28 | ///字段 29 | static const String dbFieldId = 'id'; 30 | static const String dbFieldData = 'data'; 31 | 32 | String dbName = _DEFAULT_DB; 33 | String dbTableName = _DEFAULT_TABLE; 34 | 35 | ///多实例共享连接 36 | static Database _db; 37 | 38 | ConfigProvider({this.dbTableName}); 39 | 40 | Future _ensureOpened() async { 41 | if (_db == null || !_db.isOpen) { 42 | var databasesPath = await getDatabasesPath(); 43 | String dbPath = join(databasesPath, dbName); 44 | debugPrint('open db: $dbPath'); 45 | _db = await openDatabase(dbPath, version: dbVersion, 46 | onCreate: (Database db, int version) async { 47 | debugPrint('create table $dbTableName'); 48 | await db.execute(''' 49 | create table $dbTableName ( 50 | $dbFieldId integer primary key autoincrement, 51 | $dbFieldData text not null, 52 | UNIQUE($dbFieldId) 53 | ) 54 | '''); 55 | }); 56 | } 57 | } 58 | 59 | ///添加 60 | Future add(String data) async { 61 | await _ensureOpened(); 62 | int id = await _db.rawInsert(''' 63 | INSERT INTO $dbTableName($dbFieldData) 64 | VALUES('$data'); 65 | '''); 66 | return id; 67 | } 68 | 69 | ///更新 70 | Future update(int id, String data) async { 71 | await _ensureOpened(); 72 | //根据id更新 73 | int updateCount = await _db.rawUpdate( 74 | 'UPDATE $dbTableName SET $dbFieldData = ? WHERE $dbFieldId = ?', 75 | [data, id]); 76 | debugPrint('$updateCount rows updated'); 77 | 78 | return updateCount; 79 | } 80 | 81 | ///删除 82 | Future delete(int id) async { 83 | await _ensureOpened(); 84 | return _db.delete(dbTableName, where: "$dbFieldId = ?", whereArgs: [id]); 85 | } 86 | 87 | ///所有记录 88 | Future> getAllRecord() async { 89 | await _ensureOpened(); 90 | List dataSet = 91 | await _db.query(dbTableName, columns: null, whereArgs: []); 92 | if (dataSet.length > 0) { 93 | return dataSet.map((e) => ConfigRecord.fromMap(e)).toList(); 94 | } 95 | return List(); 96 | } 97 | 98 | Future getRecord(int id) async { 99 | await _ensureOpened(); 100 | List dataSet = await _db.query(dbTableName, where: 'id = $id'); 101 | if (dataSet.length > 0) { 102 | return ConfigRecord.fromMap(dataSet.first); 103 | } 104 | return null; 105 | } 106 | 107 | Future close() async { 108 | return _db?.close(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/httphook/widgets/http_hook_domain_tree.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/cupertino.dart'; 16 | import 'package:flutter/material.dart'; 17 | import 'package:k_debug_tools_web/src/app/httphook/http_hook_bloc.dart'; 18 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 19 | import 'package:k_debug_tools_web/src/widgets/tree.dart'; 20 | import 'package:flutter_gen/gen_l10n/app_localizations.dart'; 21 | 22 | ///请求域名树 23 | class DomainTreeWidget extends StatefulWidget { 24 | @override 25 | _DomainTreeWidgetState createState() => 26 | _DomainTreeWidgetState(); 27 | } 28 | 29 | class _DomainTreeWidgetState 30 | extends State { 31 | HttpHookBloc _httpHookBloc; 32 | Map _allNodes = Map(); 33 | Node _root; 34 | Node _selectedNode; 35 | 36 | @override 37 | void initState() { 38 | _httpHookBloc = BlocProvider.of(context).first; 39 | super.initState(); 40 | } 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return TreeView( 45 | root: _buildRoot(), 46 | onTap: (n) { 47 | if (_selectedNode != n) { 48 | _selectedNode?.selected = false; 49 | _selectedNode = n; 50 | n.selected = true; 51 | _httpHookBloc.applyUriFilter(n.key); 52 | setState(() {}); 53 | } 54 | }, 55 | onExpand: (n) { 56 | n.expanded = !n.expanded; 57 | setState(() {}); 58 | }, 59 | ); 60 | } 61 | 62 | Node _buildRoot() { 63 | if (_root == null) { 64 | _root = Node(); 65 | _root.key = ''; 66 | _root.label = AppLocalizations.of(context).allHost; 67 | _root.expandable = true; 68 | _root.subs = []; 69 | } 70 | if (_httpHookBloc.httpArchiveList.isEmpty) { 71 | //清空旧数据 72 | _root.subs = []; 73 | _root.expanded = true; 74 | _allNodes.clear(); 75 | } else { 76 | _httpHookBloc.httpArchiveList.forEach((element) { 77 | List sep = element.uri.toString().split('/'); 78 | String domain = sep.length > 3 ? sep.sublist(0, 3).join('/') : ''; 79 | String path = element.uri.path; 80 | String domainPath = domain + path; 81 | //加上一级节点 域名 82 | if (_allNodes[domain] == null) { 83 | Node domainNode = Node(); 84 | _allNodes[domain] = domainNode; 85 | _root.subs.add(domainNode); 86 | 87 | domainNode.key = domain; 88 | domainNode.label = domain; 89 | domainNode.expandable = true; 90 | domainNode.subs = List(); 91 | } 92 | //加上二级节点 path 93 | if (_allNodes[domainPath] == null) { 94 | Node pathNode = Node(); 95 | _allNodes[domainPath] = pathNode; 96 | _allNodes[domain].subs.add(pathNode); 97 | 98 | pathNode.key = domainPath; 99 | pathNode.label = path; 100 | pathNode.expandable = false; 101 | } 102 | }); 103 | } 104 | return _root; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /tools_web/lib/src/app/httphookconfig/hook_config_bloc.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | import 'package:k_debug_tools_web/src/app/httphookconfig/hook_config_models.dart'; 18 | import 'package:k_debug_tools_web/src/bloc_provider.dart'; 19 | import 'package:k_debug_tools_web/src/web_http.dart'; 20 | 21 | import '../model.dart'; 22 | 23 | class HookConfigBloc extends AppBlocBase { 24 | static const String PATH = 'api/httphook/config'; 25 | 26 | final List _allConfig = List(); 27 | 28 | List get configs => _allConfig; 29 | 30 | HookConfigBloc(context) : super(context); 31 | 32 | @override 33 | void dispose() {} 34 | 35 | ///加载ThrottleConfig 36 | Future loadThrottleConfig() async { 37 | Uri uri = Uri.http(getHost(), 'api/httphook/state'); 38 | var response = await httpGet(uri); 39 | Map jsonResponse = jsonDecode(response.body); 40 | var ret = ThrottleConfig.fromJson( 41 | (jsonResponse['data'] as Map)['throttle'] as Map); 42 | return ret; 43 | } 44 | 45 | ///保存ThrottleConfig 46 | Future saveThrottleConfig(ThrottleConfig config) async { 47 | Uri uri = Uri.http(getHost(), 'api/httphook/throttle'); 48 | var response = await httpPost(uri, body: config); 49 | if (response.statusCode == 200) { 50 | return Future.value(); 51 | } else { 52 | return Future.error( 53 | ErrorResult.create('Error', jsonDecode(response.body))); 54 | } 55 | } 56 | 57 | ///读取所有配置 58 | Future> loadConfigs() async { 59 | Uri uri = Uri.http(getHost(), '$PATH/list'); 60 | var response = await httpGet(uri); 61 | Map jsonResponse = jsonDecode(response.body); 62 | if (response.statusCode == 200) { 63 | List list = (jsonResponse['data'] as Map)['config'] as List; 64 | _allConfig.clear(); 65 | list.forEach((element) { 66 | _allConfig.add(HookConfig.fromJson(element as Map)); 67 | }); 68 | return Future.value(_allConfig); 69 | } else { 70 | return Future.error( 71 | ErrorResult.create('fetch data failed', jsonResponse)); 72 | } 73 | } 74 | 75 | ///添加或更新 76 | Future save(HookConfig config) async { 77 | Uri uri = 78 | Uri.http(getHost(), config.id == null ? '$PATH/add' : '$PATH/update'); 79 | var response = await httpPost(uri, body: config); 80 | if (response.statusCode == 200) { 81 | return Future.value(); 82 | } else { 83 | return Future.error( 84 | ErrorResult.create('Error', jsonDecode(response.body))); 85 | } 86 | } 87 | 88 | ///删除 89 | Future delete(HookConfig config) async { 90 | Uri uri = Uri.http(getHost(), '$PATH/delete'); 91 | var response = await httpPost(uri, body: config); 92 | if (response.statusCode == 200) { 93 | return Future.value(); 94 | } else { 95 | return Future.error( 96 | ErrorResult.create('Error', jsonDecode(response.body))); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/http/httparchive/http_archive_detail_page.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:k_debug_tools/src/http/http_models.dart'; 17 | 18 | import '../../../k_debug_tools.dart'; 19 | import 'http_request_widget.dart'; 20 | import 'http_response_widget.dart'; 21 | 22 | ///网络请求详情 23 | class HttpArchiveDetailPage extends StatefulWidget { 24 | final HttpArchive httpArchive; 25 | 26 | HttpArchiveDetailPage(this.httpArchive); 27 | 28 | @override 29 | _HttpArchiveDetailPageState createState() => _HttpArchiveDetailPageState(); 30 | } 31 | 32 | class _HttpArchiveDetailPageState extends State 33 | with SingleTickerProviderStateMixin { 34 | final List tabs = [ 35 | new Tab(text: "request"), 36 | new Tab(text: "response"), 37 | ]; 38 | 39 | PageController _pageController; 40 | 41 | int currentIndex = 0; 42 | 43 | @override 44 | void initState() { 45 | _pageController = PageController(initialPage: 0); 46 | super.initState(); 47 | } 48 | 49 | @override 50 | void dispose() { 51 | _pageController.dispose(); 52 | super.dispose(); 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return Material( 58 | child: SafeArea( 59 | top: false, 60 | child: Container( 61 | color: Colors.white, 62 | child: Column( 63 | children: [ 64 | NavBar( 65 | title: localizationOptions.requestDetail, 66 | onBack: () { 67 | Navigator.pop(context); 68 | }, 69 | ), 70 | Expanded( 71 | child: PageView.builder( 72 | controller: _pageController, 73 | onPageChanged: _onPageChanged, 74 | itemCount: 2, 75 | itemBuilder: (BuildContext context, int index) { 76 | if (index == 0) { 77 | return RequestWidget(widget.httpArchive); 78 | } else { 79 | return ResponseWidget(widget.httpArchive); 80 | } 81 | }, 82 | )), 83 | BottomNavigationBar( 84 | currentIndex: currentIndex, 85 | onTap: _bottomTap, 86 | items: [ 87 | BottomNavigationBarItem( 88 | icon: Icon(Icons.network_wifi), title: Text('request')), 89 | BottomNavigationBarItem( 90 | icon: Icon(Icons.network_wifi), title: Text('response')), 91 | ], 92 | ) 93 | ], 94 | ), 95 | ), 96 | ), 97 | ); 98 | } 99 | 100 | void _onPageChanged(int value) { 101 | if (mounted) { 102 | setState(() { 103 | currentIndex = value; 104 | }); 105 | } 106 | } 107 | 108 | void _bottomTap(int value) { 109 | _pageController.animateToPage(value, 110 | duration: Duration(milliseconds: 300), curve: Curves.ease); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/widgets/dialog.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | 17 | import 'package:flutter/cupertino.dart'; 18 | import 'package:flutter/material.dart'; 19 | 20 | import '../../k_debug_tools.dart'; 21 | 22 | ///显示菜单对话框 类似右键菜单, Future返回选中的第x项, null没选中 23 | Future showContextMenuDialog( 24 | BuildContext ctx, 25 | List options, { 26 | String title, 27 | }) { 28 | List _optionWidget(BuildContext context) { 29 | List result = List(); 30 | for (int i = 0; i < options.length; i++) { 31 | String str = options[i]; 32 | result.add(GestureDetector( 33 | behavior: HitTestBehavior.opaque, 34 | onTap: () { 35 | Navigator.pop(context, options.indexOf(str)); 36 | }, 37 | child: Container( 38 | height: 50, 39 | padding: EdgeInsets.only(left: 8, right: 8), 40 | child: Text( 41 | str, 42 | style: TextStyle(fontSize: 16), 43 | ), 44 | ), 45 | )); 46 | } 47 | return result; 48 | } 49 | 50 | return showDialog( 51 | context: ctx, 52 | barrierDismissible: true, 53 | builder: (BuildContext context) => SimpleDialog( 54 | title: title == null 55 | ? null 56 | : Container( 57 | padding: EdgeInsets.only(bottom: 10), 58 | decoration: BoxDecoration( 59 | color: Colors.white, 60 | border: Border( 61 | bottom: 62 | BorderSide(width: 1, color: Colors.black26))), 63 | child: Text(title)), 64 | children: _optionWidget(context), 65 | titlePadding: EdgeInsets.all(10), 66 | contentPadding: EdgeInsets.all(2), 67 | )); 68 | } 69 | 70 | ///显示输入框对话框 71 | Future showInputDialog(BuildContext ctx, 72 | {String title = '', 73 | String initValue = '', 74 | TextInputType inputType = TextInputType.text}) { 75 | TextEditingController _editingController = 76 | TextEditingController.fromValue(TextEditingValue(text: initValue)); 77 | return showDialog( 78 | context: ctx, 79 | barrierDismissible: false, 80 | builder: (BuildContext context) => AlertDialog( 81 | title: Text(title), 82 | content: Container( 83 | child: TextField( 84 | keyboardType: inputType, 85 | controller: _editingController, 86 | ), 87 | ), 88 | actions: [ 89 | FlatButton( 90 | onPressed: () { 91 | Navigator.pop(context, _editingController.text); 92 | }, 93 | child: Text(localizationOptions.dialogConfirm), 94 | ), 95 | FlatButton( 96 | onPressed: () { 97 | Navigator.pop(context); 98 | }, 99 | child: Text(localizationOptions.dialogCancel), 100 | ), 101 | ], 102 | )); 103 | } 104 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/appinfo/app_info.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'package:flutter/material.dart'; 16 | import 'package:flutter/widgets.dart'; 17 | import 'package:package_info/package_info.dart'; 18 | import 'package:flutter/foundation.dart' as Foundation; 19 | import '../widgets/list_widgets.dart'; 20 | 21 | class AppInfoPage extends StatefulWidget { 22 | @override 23 | _AppInfoPageState createState() => _AppInfoPageState(); 24 | } 25 | 26 | class _AppInfoPageState extends State { 27 | List _widgets = List(); 28 | 29 | @override 30 | void initState() { 31 | _buildInfo(); 32 | super.initState(); 33 | } 34 | 35 | @override 36 | Widget build(BuildContext context) { 37 | return ListView.separated( 38 | controller: ScrollController(), 39 | padding: EdgeInsets.fromLTRB(16, 0, 16, 0), 40 | itemCount: _widgets.length, 41 | itemBuilder: (BuildContext context, int index) { 42 | return _widgets[index]; 43 | }, 44 | separatorBuilder: (BuildContext context, int index) { 45 | return Divider(height: 1, color: Color(0xff000000)); 46 | }, 47 | ); 48 | } 49 | 50 | void _buildInfo() async { 51 | _widgets.clear(); 52 | PackageInfo packageInfo = await PackageInfo.fromPlatform(); 53 | 54 | String appName = packageInfo.appName; 55 | String packageName = packageInfo.packageName; 56 | String version = packageInfo.version; 57 | String buildNumber = packageInfo.buildNumber; 58 | _widgets.add(SimpleListInfoWidget( 59 | label: 'appName', 60 | value: appName, 61 | )); 62 | _widgets.add(SimpleListInfoWidget( 63 | label: 'package', 64 | value: packageName, 65 | )); 66 | _widgets.add(SimpleListInfoWidget( 67 | label: 'version', 68 | value: version, 69 | )); 70 | _widgets.add(SimpleListInfoWidget( 71 | label: 'buildNumber', 72 | value: buildNumber, 73 | )); 74 | 75 | if (Foundation.kDebugMode) { 76 | _widgets.add(SimpleListInfoWidget( 77 | label: 'runMode', 78 | value: 'Debug', 79 | )); 80 | } 81 | 82 | if (Foundation.kProfileMode) { 83 | _widgets.add(SimpleListInfoWidget( 84 | label: 'runMode', 85 | value: 'Profile', 86 | )); 87 | } 88 | 89 | if (Foundation.kReleaseMode) { 90 | _widgets.add(SimpleListInfoWidget( 91 | label: 'runMode', 92 | value: 'Release', 93 | )); 94 | } 95 | 96 | _widgets.add(SimpleListInfoWidget( 97 | label: 'buildTime', 98 | value: const String.fromEnvironment('BUILD_TIME'), 99 | )); 100 | 101 | _widgets.add(SimpleListInfoWidget( 102 | label: 'gitBranch', 103 | value: const String.fromEnvironment('GIT_BRANCH'), 104 | )); 105 | 106 | _widgets.add(SimpleListInfoWidget( 107 | label: 'gitCommit', 108 | value: const String.fromEnvironment('GIT_COMMIT'), 109 | )); 110 | 111 | _widgets.add(SimpleListInfoWidget( 112 | label: 'jenkinsBuildId', 113 | value: const String.fromEnvironment('JENKINS_BUILD_ID'), 114 | )); 115 | 116 | setState(() {}); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/http/httphook/http_hook_controller.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:convert'; 16 | 17 | import 'package:flutter/cupertino.dart'; 18 | import 'package:k_debug_tools/src/webserver/handlers/ws_handler.dart'; 19 | 20 | import '../http_float_button.dart'; 21 | import '../http_models.dart'; 22 | import 'config_provider.dart'; 23 | import 'config_models.dart'; 24 | import 'http_hook_local_service.dart'; 25 | 26 | ///网络拦截抓包及修改控制 27 | class HttpHookController { 28 | HttpHookController._privateConstructor(); 29 | 30 | static final HttpHookController instance = 31 | HttpHookController._privateConstructor(); 32 | 33 | static final int maxArchiveCount = 200; 34 | 35 | ///请求历史记录 36 | List _archiveList; 37 | 38 | ///默认不打开,不持久化 每次都需要设置开启 39 | final ValueNotifier enableHook = ValueNotifier(false); 40 | 41 | ConfigProvider _hookConfigProvider; 42 | HttpHookLocalService _localService; 43 | 44 | final List _hookConfigs = List(); 45 | 46 | List get hookConfigs => _hookConfigs.toList(growable: false); 47 | 48 | List get httpArchives => _archiveList.toList(growable: false); 49 | 50 | Future init() async { 51 | _hookConfigProvider = ConfigProvider(dbTableName: 'hook_config'); 52 | _localService = HttpHookLocalService.instance; 53 | _archiveList = List(); 54 | } 55 | 56 | ///设置 57 | void setEnable(bool enable) { 58 | enableHook.value = enable; 59 | if (enable) { 60 | _reloadConfig(); 61 | _localService.start(); 62 | showHttpFloatBtn(); 63 | } else { 64 | _localService.stop(); 65 | dismissHttpFloatBtn(); 66 | } 67 | } 68 | 69 | Uri mapLocalUri(HookConfig config) { 70 | return Uri.parse(_localService.mapLocalServiceUri + '?id=${config?.id}'); 71 | } 72 | 73 | Future _reloadConfig() async { 74 | _hookConfigs.clear(); 75 | List records = await _hookConfigProvider.getAllRecord(); 76 | records.forEach((element) { 77 | _hookConfigs.add(HookConfig.fromRecord(element)..id = element.id); 78 | }); 79 | } 80 | 81 | Future add(HookConfig config) async { 82 | int id = await _hookConfigProvider.add(jsonEncode(config)); 83 | debugPrint('HookConfig added, id: $id'); 84 | await _reloadConfig(); 85 | } 86 | 87 | Future update(HookConfig config) async { 88 | int rows = await _hookConfigProvider.update(config.id, jsonEncode(config)); 89 | debugPrint('$rows hookConfig updated'); 90 | await _reloadConfig(); 91 | } 92 | 93 | Future delete(int id) async { 94 | int rows = await _hookConfigProvider.delete(id); 95 | debugPrint('$rows hookConfig deleted'); 96 | await _reloadConfig(); 97 | } 98 | 99 | void addArchive(HttpArchive archive) { 100 | _archiveList.add(archive); 101 | if (_archiveList.length > maxArchiveCount) { 102 | _archiveList.removeAt(0); 103 | } 104 | } 105 | 106 | void clearArchive() { 107 | _archiveList.clear(); 108 | } 109 | 110 | void sendToWeb(HttpArchive archive) { 111 | //通过websocket发送 112 | WebSocketHandler.broadcastJson('httphook', 0, archive.toJson()); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /tools_plugin/lib/src/webserver/handlers/sp_handler.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Kwai, Inc. All rights reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import 'dart:async'; 16 | import 'dart:convert'; 17 | 18 | import 'package:shared_preferences/shared_preferences.dart'; 19 | import 'package:shelf/shelf.dart'; 20 | import 'package:shelf_router/shelf_router.dart' as shelf; 21 | 22 | import '../handler_def.dart'; 23 | 24 | class SharedPreferencesHandler extends AbsAppHandler { 25 | SharedPreferences _sharedPreferences; 26 | 27 | @override 28 | shelf.Router get router { 29 | SharedPreferences.getInstance().then((value) => _sharedPreferences = value); 30 | final router = shelf.Router(); 31 | //list key value 32 | router.get('/list', _list); 33 | router.post('/delete', _delete); 34 | router.post('/commit', _commit); 35 | 36 | router.all('/', (Request request) => notFound()); 37 | 38 | return router; 39 | } 40 | 41 | Future _ensureInitialized() async { 42 | if (_sharedPreferences == null) { 43 | _sharedPreferences = await SharedPreferences.getInstance(); 44 | } 45 | } 46 | 47 | ///读取数据 48 | Future _list(Request request) async { 49 | await _ensureInitialized(); 50 | await _sharedPreferences.reload(); 51 | Map data = Map(); 52 | List kvs = List(); 53 | data['list'] = kvs; 54 | _sharedPreferences.getKeys().forEach((key) { 55 | kvs.add(buildDataModel(key: key, value: _sharedPreferences.get(key))); 56 | }); 57 | return ok(data); 58 | } 59 | 60 | ///删除 61 | Future _delete(Request request) async { 62 | await _ensureInitialized(); 63 | await _sharedPreferences.reload(); 64 | Map body = jsonDecode(await request.readAsString()); 65 | String key = body['key']; 66 | _sharedPreferences.remove(key); 67 | return ok(); 68 | } 69 | 70 | ///新增 或 修改 71 | Future _commit(Request request) async { 72 | await _ensureInitialized(); 73 | await _sharedPreferences.reload(); 74 | Map body = jsonDecode(await request.readAsString()); 75 | String key = body['key']; 76 | String value = body['value']; 77 | String valueType = body['valueType']; 78 | try { 79 | switch (valueType) { 80 | case 'String': 81 | _sharedPreferences.setString(key, value); 82 | break; 83 | case 'bool': 84 | _sharedPreferences.setBool(key, value?.toLowerCase() == 'true'); 85 | break; 86 | case 'int': 87 | _sharedPreferences.setInt(key, int.parse(value)); 88 | break; 89 | case 'double': 90 | _sharedPreferences.setDouble(key, double.parse(value)); 91 | break; 92 | default: 93 | return error('unknown valueType'); 94 | break; 95 | } 96 | } catch (e) { 97 | return error('commit error: $e'); 98 | } 99 | return ok(); 100 | } 101 | 102 | Object buildDataModel({String key, Object value}) { 103 | Map model = Map(); 104 | model['key'] = key; 105 | model['value'] = value; 106 | model['valueType'] = value?.runtimeType?.toString(); 107 | return model; 108 | } 109 | } 110 | --------------------------------------------------------------------------------