diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 18322f7..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1,12 +0,0 @@ -# These are supported funding model platforms - -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: https://v7lin.github.io/docsify/#/navbar/sponsor # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.gitignore b/.gitignore index 95abf25..96486fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp .DS_Store -.dart_tool/ +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ -.packages -.pub/ - -build/ - -# +# IntelliJ related *.iml +*.ipr +*.iws .idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/.metadata b/.metadata index 53b454c..5bfec1b 100644 --- a/.metadata +++ b/.metadata @@ -1,10 +1,33 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled and should not be manually edited. +# This file should be version controlled. version: - revision: b041144f833e05cf463b8887fa12efdec9493488 + revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 channel: stable project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + - platform: android + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + - platform: ios + create_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + base_revision: ee4e09cce01d6f2d7f4baebd247fde02e5008851 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d53cc4..f82e89a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 4.0.0 + +* 升级 Flutter 3.0 +* 升级 Android/iOS SDK +* break change: 官方标准化插件 + ## 3.1.0 * 升级 Android/iOS SDK diff --git a/README.md b/README.md index 8abff49..19356a0 100644 --- a/README.md +++ b/README.md @@ -26,15 +26,6 @@ flutter版腾讯(QQ)SDK ## android -```groovy -buildscript { - dependencies { - // Android 11兼容,需升级Gradle到3.5.4/3.6.4/4.x.y - classpath 'com.android.tools.build:gradle:3.5.4' - } -} -``` - ```groovy android { defaultConfig{ @@ -121,24 +112,25 @@ Capabilities -> Associated Domain -> Domain -> applinks:${your applinks} |QZone|支持|不支持|不支持|不支持|不支持|支持| * break change - * 3.1.0: 新增 setIsPermissionGranted 函数,设置是否已授权获取设备信息/是否同意隐私协议 - * 3.0.0: 重构 - * 2.1.0: nullsafety & 不再支持 Android embedding v1 & Tencent 单例 + * 4.0.0: 按标准插件书写重构 + * 3.1.0: 新增 setIsPermissionGranted 函数,设置是否已授权获取设备信息/是否同意隐私协议 + * 3.0.0: 重构 + * 2.1.0: nullsafety & 不再支持 Android embedding v1 & Tencent 单例 * compat - * flutter 2.5 兼容问题 [issues/54](https://github.com/RxReader/tencent_kit/issues/54) - ``` - post_install do |installer| - installer.pods_project.targets.each do |target| - flutter_additional_ios_build_settings(target) - # 兼容 Flutter 2.5 - target.build_configurations.each do |config| - # config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' - config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 arm64' - end + * flutter 2.5 兼容问题 [issues/54](https://github.com/RxReader/tencent_kit/issues/54) + ``` + post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + # 兼容 Flutter 2.5 + target.build_configurations.each do |config| + # config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '9.0' + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'i386 arm64' end end - ``` + end + ``` * snapshot diff --git a/analysis_options.yaml b/analysis_options.yaml index 41cde2e..2e4f838 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -5,39 +5,44 @@ # # For a list of lints, see: http://dart-lang.github.io/linter/lints/ # See the configuration guide for more -# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer +# https://github.com/dart-lang/sdk/tree/main/pkg/analyzer#configuring-the-analyzer # # There are other similar analysis options files in the flutter repos, # which should be kept in sync with this file: # # - analysis_options.yaml (this file) -# - packages/flutter/lib/analysis_options_user.yaml # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml # - https://github.com/flutter/engine/blob/master/analysis_options.yaml +# - https://github.com/flutter/packages/blob/master/analysis_options.yaml # # This file contains the analysis options used by Flutter tools, such as IntelliJ, # Android Studio, and the `flutter analyze` command. analyzer: - strong-mode: - implicit-casts: false - implicit-dynamic: false + language: + strict-raw-types: true errors: # treat missing required parameters as a warning (not a hint) missing_required_param: warning # treat missing returns as a warning (not a hint) missing_return: warning - # allow having TODOs in the code + # allow having TODO comments in the code todo: ignore # allow self-reference to deprecated members (we do this because otherwise we have # to annotate every member in every test, assert, etc, when we deprecate something) deprecated_member_use_from_same_package: ignore - # Ignore analyzer hints for updating pubspecs when using Future or - # Stream and not importing dart:async - # Please see https://github.com/flutter/flutter/pull/24528 for details. - sdk_version_async_exported_from_core: ignore + # TODO(ianh): https://github.com/flutter/flutter/issues/74381 + # Clean up existing unnecessary imports, and remove line to ignore. + unnecessary_import: ignore + # Turned off until null-safe rollout is complete. + unnecessary_null_comparison: ignore exclude: + - "bin/cache/**" + # Ignore protoc generated files + - "dev/conductor/lib/proto/*" + # - "lib/*.g.dart" + - "lib/**/*.g.dart" linter: rules: @@ -49,65 +54,71 @@ linter: # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 - always_require_non_null_named_parameters - always_specify_types - - always_use_package_imports # we do this commonly + # - always_use_package_imports # we do this commonly - annotate_overrides # - avoid_annotating_with_dynamic # conflicts with always_specify_types - # - avoid_as # required for implicit-casts: true - avoid_bool_literals_in_conditional_expressions - # - avoid_catches_without_on_clauses # we do this commonly - # - avoid_catching_errors # we do this commonly + # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 + # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 - avoid_classes_with_only_static_members - # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_double_and_int_checks + - avoid_dynamic_calls - avoid_empty_else - avoid_equals_and_hash_code_on_mutable_classes - # - avoid_escaping_inner_quotes # not yet tested + - avoid_escaping_inner_quotes - avoid_field_initializers_in_const_classes + # - avoid_final_parameters # incompatible with prefer_final_parameters - avoid_function_literals_in_foreach_calls - # - avoid_implementing_value_types # not yet tested + - avoid_implementing_value_types - avoid_init_to_null - # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_js_rounded_ints + # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to - avoid_null_checks_in_equality_operators - # - avoid_positional_boolean_parameters # not yet tested - # - avoid_print # not yet tested + # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it + - avoid_print # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) - # - avoid_redundant_argument_values # not yet tested + - avoid_redundant_argument_values - avoid_relative_lib_imports - avoid_renaming_method_parameters - avoid_return_types_on_setters - # - avoid_returning_null # there are plenty of valid reasons to return null - # - avoid_returning_null_for_future # not yet tested + # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated + - avoid_returning_null_for_future - avoid_returning_null_for_void - # - avoid_returning_this # there are plenty of valid reasons to return this - # - avoid_setters_without_getters # not yet tested + # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives + - avoid_setters_without_getters - avoid_shadowing_type_parameters - avoid_single_cascade_in_expression_statements - avoid_slow_async_io - # - avoid_type_to_string # we do this commonly + - avoid_type_to_string - avoid_types_as_parameter_names # - avoid_types_on_closure_parameters # conflicts with always_specify_types - # - avoid_unnecessary_containers # not yet tested + - avoid_unnecessary_containers - avoid_unused_constructor_parameters - avoid_void_async - # - avoid_web_libraries_in_flutter # not yet tested + # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere - await_only_futures - camel_case_extensions - camel_case_types - cancel_subscriptions - # - cascade_invocations # not yet tested + # - cascade_invocations # doesn't match the typical style of this repo - cast_nullable_to_non_nullable # - close_sinks # not reliable enough - # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 + # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 + # - conditional_uri_does_not_exist # not yet tested # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 - control_flow_in_finally # - curly_braces_in_flow_control_structures # not required by flutter style - # - diagnostic_describe_all_properties # not yet tested + - depend_on_referenced_packages + - deprecated_consistency + # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) - directives_ordering - # - do_not_use_environment # we do this commonly + # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic - empty_catches - empty_constructor_bodies - empty_statements + - eol_at_end_of_file - exhaustive_cases - - file_names # not yet tested + - file_names - flutter_style_todos - hash_and_equals - implementation_imports @@ -117,24 +128,28 @@ linter: - leading_newlines_in_multiline_strings - library_names - library_prefixes + - library_private_types_in_public_api # - lines_longer_than_80_chars # not required by flutter style - list_remove_unrelated_type - # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 - # - missing_whitespace_between_adjacent_strings # not yet tested + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 + - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - # - no_default_cases # too many false positives + - no_default_cases - no_duplicate_case_values + - no_leading_underscores_for_library_prefixes + - no_leading_underscores_for_local_identifiers - no_logic_in_create_state # - no_runtimeType_toString # ok in tests; we enable this only in packages/ - non_constant_identifier_names + - noop_primitive_operations - null_check_on_nullable_type_parameter - # - null_closures # not required by flutter style + - null_closures # - omit_local_variable_types # opposite of always_specify_types # - one_member_abstracts # too many false positives - # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 + - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al - overridden_fields - package_api_docs - # - package_names # non conforming packages in sdk + - package_names - package_prefixed_library_names # - parameter_assignments # we do this commonly - prefer_adjacent_string_concatenation @@ -142,10 +157,10 @@ linter: # - prefer_asserts_with_message # not required by flutter style - prefer_collection_literals - prefer_conditional_assignment - - prefer_const_constructors + # - prefer_const_constructors - prefer_const_constructors_in_immutables - prefer_const_declarations - - prefer_const_literals_to_create_immutables + # - prefer_const_literals_to_create_immutables # - prefer_constructors_over_static_methods # far too many false positives - prefer_contains # - prefer_double_quotes # opposite of prefer_single_quotes @@ -154,33 +169,38 @@ linter: - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals + # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments - prefer_for_elements_to_map_fromIterable - prefer_foreach - # - prefer_function_declarations_over_variables # not yet tested + - prefer_function_declarations_over_variables - prefer_generic_function_type_aliases - prefer_if_elements_to_conditional_expressions - prefer_if_null_operators - prefer_initializing_formals - prefer_inlined_adds - # - prefer_int_literals # not yet tested - # - prefer_interpolation_to_compose_strings # not yet tested + # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants + - prefer_interpolation_to_compose_strings - prefer_is_empty - prefer_is_not_empty - prefer_is_not_operator - prefer_iterable_whereType - # - prefer_mixin # https://github.com/dart-lang/language/issues/32 - # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 - # - prefer_relative_imports # not yet tested + # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 + # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere + - prefer_null_aware_operators + # - prefer_relative_imports - prefer_single_quotes - prefer_spread_collections - prefer_typing_uninitialized_variables - prefer_void_to_null - # - provide_deprecation_message # not yet tested + - provide_deprecation_message # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml - recursive_getters - # - sized_box_for_whitespace # not yet tested + # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 + - secure_pubspec_urls + - sized_box_for_whitespace + # - sized_box_shrink_expand # not yet tested - slash_for_doc_comments - # - sort_child_properties_last # not yet tested + - sort_child_properties_last - sort_constructors_first # - sort_pub_dependencies # prevents separating pinned transitive dependencies - sort_unnamed_constructors_first @@ -189,36 +209,43 @@ linter: - tighten_type_of_initializing_formals # - type_annotate_public_apis # subset of always_specify_types - type_init_formals - - unawaited_futures # too many false positives - # - unnecessary_await_in_return # not yet tested + # - unawaited_futures # too many false positives, especially with the way AnimationController works + - unnecessary_await_in_return - unnecessary_brace_in_string_interps - unnecessary_const + - unnecessary_constructor_name # - unnecessary_final # conflicts with prefer_final_locals - unnecessary_getters_setters # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_late - unnecessary_new - unnecessary_null_aware_assignments - # - unnecessary_null_checks # not yet tested + - unnecessary_null_checks - unnecessary_null_in_if_null_operators - unnecessary_nullable_for_final_variable_declarations - unnecessary_overrides - unnecessary_parenthesis - # - unnecessary_raw_strings # not yet tested + # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint - unnecessary_statements - unnecessary_string_escapes - unnecessary_string_interpolations - unnecessary_this - unrelated_type_equality_checks - # - unsafe_html # not yet tested + - unsafe_html + - use_build_context_synchronously + # - use_decorated_box # not yet tested - use_full_hex_values_for_flutter_colors - # - use_function_type_syntax_for_parameters # not yet tested + - use_function_type_syntax_for_parameters + - use_if_null_to_convert_nulls_to_bools - use_is_even_rather_than_modulo - # - use_key_in_widget_constructors # not yet tested + - use_key_in_widget_constructors - use_late_for_private_fields_and_variables + - use_named_constants - use_raw_strings - use_rethrow_when_possible - # - use_setters_to_change_properties # not yet tested + - use_setters_to_change_properties # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + - use_test_throws_matchers # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review - valid_regexps - void_checks diff --git a/android/.gitignore b/android/.gitignore index c6cbe56..161bdcd 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -6,3 +6,4 @@ .DS_Store /build /captures +.cxx diff --git a/android/build.gradle b/android/build.gradle index 5039580..e1a2181 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ group 'io.github.v7lin.tencent_kit' -version '3.1.0' +version '4.0.0' buildscript { repositories { @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.1.2' } } @@ -24,6 +24,11 @@ apply plugin: 'com.android.library' android { compileSdkVersion 31 + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + // useLibrary 'org.apache.http.legacy' resourcePrefix 'tencent_kit' @@ -54,5 +59,4 @@ android { dependencies { // vendorImplementation fileTree(include: ['*.jar'], dir: 'libs') -// vendorImplementation 'com.tencent.tauth:qqopensdk:3.53.0' } diff --git a/android/gradle.properties b/android/gradle.properties deleted file mode 100644 index 38c8d45..0000000 --- a/android/gradle.properties +++ /dev/null @@ -1,4 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true -android.useAndroidX=true -android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 3c9d085..0000000 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/android/libs/open_sdk_3.5.10.3_r593ae92_lite.jar b/android/libs/open_sdk_3.5.12.2_r97423a8_lite.jar similarity index 62% rename from android/libs/open_sdk_3.5.10.3_r593ae92_lite.jar rename to android/libs/open_sdk_3.5.12.2_r97423a8_lite.jar index 1536896..6e0b4d1 100644 Binary files a/android/libs/open_sdk_3.5.10.3_r593ae92_lite.jar and b/android/libs/open_sdk_3.5.12.2_r97423a8_lite.jar differ diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 73c4e43..768529d 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + package="io.github.v7lin.tencent_kit"> map = new HashMap<>(); + final Map map = new HashMap<>(); try { if (o != null && o instanceof JSONObject) { - JSONObject object = (JSONObject) o; - int ret = !object.isNull(ARGUMENT_KEY_RESULT_RET) ? object.getInt(ARGUMENT_KEY_RESULT_RET) : TencentRetCode.RET_FAILED; - String msg = !object.isNull(ARGUMENT_KEY_RESULT_MSG) ? object.getString(ARGUMENT_KEY_RESULT_MSG) : null; + final JSONObject object = (JSONObject) o; + final int ret = !object.isNull("ret") ? object.getInt("ret") : TencentRetCode.RET_FAILED; + final String msg = !object.isNull("msg") ? object.getString("msg") : null; if (ret == TencentRetCode.RET_SUCCESS) { - String openId = !object.isNull(ARGUMENT_KEY_RESULT_OPENID) ? object.getString(ARGUMENT_KEY_RESULT_OPENID) : null; - String accessToken = !object.isNull(ARGUMENT_KEY_RESULT_ACCESS_TOKEN) ? object.getString(ARGUMENT_KEY_RESULT_ACCESS_TOKEN) : null; - int expiresIn = !object.isNull(ARGUMENT_KEY_RESULT_EXPIRES_IN) ? object.getInt(ARGUMENT_KEY_RESULT_EXPIRES_IN) : 0; - long createAt = System.currentTimeMillis(); + final String openId = !object.isNull("openid") ? object.getString("openid") : null; + final String accessToken = !object.isNull("access_token") ? object.getString("access_token") : null; + final int expiresIn = !object.isNull("expires_in") ? object.getInt("expires_in") : 0; + final long createAt = System.currentTimeMillis(); if (!TextUtils.isEmpty(openId) && !TextUtils.isEmpty(accessToken)) { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_SUCCESS); - map.put(ARGUMENT_KEY_RESULT_OPENID, openId); - map.put(ARGUMENT_KEY_RESULT_ACCESS_TOKEN, accessToken); - map.put(ARGUMENT_KEY_RESULT_EXPIRES_IN, expiresIn); - map.put(ARGUMENT_KEY_RESULT_CREATE_AT, createAt); + map.put("ret", TencentRetCode.RET_SUCCESS); + map.put("openid", openId); + map.put("access_token", accessToken); + map.put("expires_in", expiresIn); + map.put("create_at", createAt); } else { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, "openId or accessToken is null."); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", "openId or accessToken is null."); } } else { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, msg); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", msg); } } } catch (JSONException e) { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage()); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", e.getMessage()); } if (channel != null) { - channel.invokeMethod(METHOD_ONLOGINRESP, map); + channel.invokeMethod("onLoginResp", map); } } @Override public void onError(UiError uiError) { // 登录失败 - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, uiError.errorMessage); + final Map map = new HashMap<>(); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", uiError.errorMessage); if (channel != null) { - channel.invokeMethod(METHOD_ONLOGINRESP, map); + channel.invokeMethod("onLoginResp", map); } } @Override public void onCancel() { // 取消登录 - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL); + final Map map = new HashMap<>(); + map.put("ret", TencentRetCode.RET_USERCANCEL); if (channel != null) { - channel.invokeMethod(METHOD_ONLOGINRESP, map); + channel.invokeMethod("onLoginResp", map); } } @@ -295,25 +257,25 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } private void shareMood(@NonNull MethodCall call, @NonNull Result result) { - int scene = call.argument(ARGUMENT_KEY_SCENE); + final int scene = call.argument("scene"); if (scene == TencentScene.SCENE_QZONE) { - String summary = call.argument(ARGUMENT_KEY_SUMMARY); - List imageUris = call.argument(ARGUMENT_KEY_IMAGEURIS); - String videoUri = call.argument(ARGUMENT_KEY_VIDEOURI); + final String summary = call.argument("summary"); + final List imageUris = call.argument("imageUris"); + final String videoUri = call.argument("videoUri"); - Bundle params = new Bundle(); + final Bundle params = new Bundle(); if (!TextUtils.isEmpty(summary)) { params.putString(QzonePublish.PUBLISH_TO_QZONE_SUMMARY, summary); } if (imageUris != null && !imageUris.isEmpty()) { - ArrayList uris = new ArrayList<>(); + final ArrayList uris = new ArrayList<>(); for (String imageUri : imageUris) { uris.add(Uri.parse(imageUri).getPath()); } params.putStringArrayList(QzonePublish.PUBLISH_TO_QZONE_IMAGE_URL, uris); } if (!TextUtils.isEmpty(videoUri)) { - String videoPath = Uri.parse(videoUri).getPath(); + final String videoPath = Uri.parse(videoUri).getPath(); params.putString(QzonePublish.PUBLISH_TO_QZONE_VIDEO_PATH, videoPath); params.putInt(QzonePublish.PUBLISH_TO_QZONE_KEY_TYPE, QzonePublish.PUBLISH_TO_QZONE_TYPE_PUBLISHVIDEO); } else { @@ -327,16 +289,16 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } private void shareText(@NonNull MethodCall call, @NonNull Result result) { - int scene = call.argument(ARGUMENT_KEY_SCENE); + final int scene = call.argument("scene"); if (scene == TencentScene.SCENE_QQ) { - String summary = call.argument(ARGUMENT_KEY_SUMMARY); - Intent sendIntent = new Intent(); + final String summary = call.argument("summary"); + final Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, summary); sendIntent.setType("text/*"); // 普通大众版 > 办公简洁版 > 急速轻聊版 - PackageManager packageManager = applicationContext.getPackageManager(); - List infos = packageManager.getInstalledPackages(0); + final PackageManager packageManager = applicationContext.getPackageManager(); + final List infos = packageManager.getInstalledPackages(0); if (infos != null && !infos.isEmpty()) { for (String packageName : Arrays.asList("com.tencent.mobileqq", "com.tencent.tim", "com.tencent.qqlite")) { for (PackageInfo info : infos) { @@ -356,13 +318,13 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } private void shareImage(@NonNull MethodCall call, @NonNull Result result) { - int scene = call.argument(ARGUMENT_KEY_SCENE); + final int scene = call.argument("scene"); if (scene == TencentScene.SCENE_QQ) { - String imageUri = call.argument(ARGUMENT_KEY_IMAGEURI); - String appName = call.argument(ARGUMENT_KEY_APPNAME); - int extInt = call.argument(ARGUMENT_KEY_EXTINT); + final String imageUri = call.argument("imageUri"); + final String appName = call.argument("appName"); + final int extInt = call.argument("extInt"); - Bundle params = new Bundle(); + final Bundle params = new Bundle(); params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_IMAGE); params.putString(QQShare.SHARE_TO_QQ_IMAGE_LOCAL_URL, Uri.parse(imageUri).getPath()); if (!TextUtils.isEmpty(appName)) { @@ -377,15 +339,15 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } private void shareMusic(@NonNull MethodCall call, @NonNull Result result) { - int scene = call.argument(ARGUMENT_KEY_SCENE); + final int scene = call.argument("scene"); if (scene == TencentScene.SCENE_QQ) { - String title = call.argument(ARGUMENT_KEY_TITLE); - String summary = call.argument(ARGUMENT_KEY_SUMMARY); - String imageUri = call.argument(ARGUMENT_KEY_IMAGEURI); - String musicUrl = call.argument(ARGUMENT_KEY_MUSICURL); - String targetUrl = call.argument(ARGUMENT_KEY_TARGETURL); - String appName = call.argument(ARGUMENT_KEY_APPNAME); - int extInt = call.argument(ARGUMENT_KEY_EXTINT); + final String title = call.argument("title"); + final String summary = call.argument("summary"); + final String imageUri = call.argument("imageUri"); + final String musicUrl = call.argument("musicUrl"); + final String targetUrl = call.argument("targetUrl"); + final String appName = call.argument("appName"); + final int extInt = call.argument("extInt"); Bundle params = new Bundle(); params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_AUDIO); @@ -395,7 +357,7 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } if (!TextUtils.isEmpty(imageUri)) { Uri uri = Uri.parse(imageUri); - if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) { + if (TextUtils.equals("file", uri.getScheme())) { params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath()); } else { params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri); @@ -415,15 +377,15 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR } private void shareWebpage(@NonNull MethodCall call, @NonNull Result result) { - int scene = call.argument(ARGUMENT_KEY_SCENE); - String title = call.argument(ARGUMENT_KEY_TITLE); - String summary = call.argument(ARGUMENT_KEY_SUMMARY); - String imageUri = call.argument(ARGUMENT_KEY_IMAGEURI); - String targetUrl = call.argument(ARGUMENT_KEY_TARGETURL); - String appName = call.argument(ARGUMENT_KEY_APPNAME); - int extInt = call.argument(ARGUMENT_KEY_EXTINT); + final int scene = call.argument("scene"); + final String title = call.argument("title"); + final String summary = call.argument("summary"); + final String imageUri = call.argument("imageUri"); + final String targetUrl = call.argument("targetUrl"); + final String appName = call.argument("appName"); + final int extInt = call.argument("extInt"); - Bundle params = new Bundle(); + final Bundle params = new Bundle(); switch (scene) { case TencentScene.SCENE_QQ: params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT); @@ -432,8 +394,8 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR params.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary); } if (!TextUtils.isEmpty(imageUri)) { - Uri uri = Uri.parse(imageUri); - if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) { + final Uri uri = Uri.parse(imageUri); + if (TextUtils.equals("file", uri.getScheme())) { params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath()); } else { params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri); @@ -455,9 +417,9 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, summary); } if (!TextUtils.isEmpty(imageUri)) { - ArrayList uris = new ArrayList<>(); - Uri uri = Uri.parse(imageUri); - if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) { + final ArrayList uris = new ArrayList<>(); + final Uri uri = Uri.parse(imageUri); + if (TextUtils.equals("file", uri.getScheme())) { uris.add(uri.getPath()); } else { uris.add(imageUri); @@ -478,44 +440,44 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityR private IUiListener shareListener = new IUiListener() { @Override public void onComplete(Object o) { - Map map = new HashMap<>(); + final Map map = new HashMap<>(); try { if (o != null && o instanceof JSONObject) { - JSONObject object = (JSONObject) o; - int ret = !object.isNull(ARGUMENT_KEY_RESULT_RET) ? object.getInt(ARGUMENT_KEY_RESULT_RET) : TencentRetCode.RET_FAILED; - String msg = !object.isNull(ARGUMENT_KEY_RESULT_MSG) ? object.getString(ARGUMENT_KEY_RESULT_MSG) : null; + final JSONObject object = (JSONObject) o; + final int ret = !object.isNull("ret") ? object.getInt("ret") : TencentRetCode.RET_FAILED; + final String msg = !object.isNull("msg") ? object.getString("msg") : null; if (ret == TencentRetCode.RET_SUCCESS) { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_SUCCESS); + map.put("ret", TencentRetCode.RET_SUCCESS); } else { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, msg); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", msg); } } } catch (JSONException e) { - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage()); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", e.getMessage()); } if (channel != null) { - channel.invokeMethod(METHOD_ONSHARERESP, map); + channel.invokeMethod("onShareResp", map); } } @Override public void onError(UiError error) { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON); - map.put(ARGUMENT_KEY_RESULT_MSG, error.errorMessage); + final Map map = new HashMap<>(); + map.put("ret", TencentRetCode.RET_COMMON); + map.put("msg", error.errorMessage); if (channel != null) { - channel.invokeMethod(METHOD_ONSHARERESP, map); + channel.invokeMethod("onShareResp", map); } } @Override public void onCancel() { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL); + final Map map = new HashMap<>(); + map.put("ret", TencentRetCode.RET_USERCANCEL); if (channel != null) { - channel.invokeMethod(METHOD_ONSHARERESP, map); + channel.invokeMethod("onShareResp", map); } } diff --git a/example/.gitignore b/example/.gitignore index 0fa6b67..a8e938c 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -8,6 +8,7 @@ .buildlog/ .history .svn/ +migrate_working_dir/ # IntelliJ related *.iml diff --git a/example/.metadata b/example/.metadata deleted file mode 100644 index 7c361dd..0000000 --- a/example/.metadata +++ /dev/null @@ -1,10 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: b041144f833e05cf463b8887fa12efdec9493488 - channel: stable - -project_type: app diff --git a/example/README.md b/example/README.md index 7f6c3ea..6f6915f 100644 --- a/example/README.md +++ b/example/README.md @@ -8,9 +8,9 @@ This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: -- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) -For help getting started with Flutter, view our -[online documentation](https://flutter.dev/docs), which offers tutorials, +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, samples, guidance on mobile development, and a full API reference. diff --git a/example/android/.gitignore b/example/android/.gitignore index 0a741cb..6f56801 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -9,3 +9,5 @@ GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 3fc46bb..83dbc89 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -27,14 +27,18 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { compileSdkVersion flutter.compileSdkVersion + ndkVersion flutter.ndkVersion - lintOptions { - disable 'InvalidPackage' + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "io.github.v7lin.tencent_kit_example" + // You can update the following values to match your application needs. + // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. minSdkVersion flutter.minSdkVersion targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 7b2e0c9..9d244b0 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index e7521b8..4edd6b1 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,11 +1,6 @@ - - + + + + + + + diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 1f83a33..cb1ef88 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,18 +1,18 @@ - - - diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index 7b2e0c9..9d244b0 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,6 +1,7 @@ - diff --git a/example/android/build.gradle b/example/android/build.gradle index 4256f91..83ae220 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:7.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 38c8d45..94adc3a 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,3 @@ org.gradle.jvmargs=-Xmx1536M -android.enableR8=true android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index bc6a58a..cc5527d 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index d3b6a40..44e62bc 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,7 +1,3 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - include ':app' def localPropertiesFile = new File(rootProject.projectDir, "local.properties") diff --git a/example/ios/.gitignore b/example/ios/.gitignore index e96ef60..7a7f987 100644 --- a/example/ios/.gitignore +++ b/example/ios/.gitignore @@ -1,3 +1,4 @@ +**/dgph *.mode1v3 *.mode2v3 *.moved-aside @@ -18,6 +19,7 @@ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig +Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index f2872cf..8d4492f 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) + en CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index e8efba1..ec97fc6 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 399e934..c4855bf 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1,2 @@ -#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 6576e5a..43cb163 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -3,20 +3,20 @@ PODS: - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - path_provider (0.0.1): + - path_provider_ios (0.0.1): - Flutter - sqflite (0.0.2): - Flutter - FMDB (>= 2.7.5) - - tencent_kit (3.1.0): + - tencent_kit (4.0.0): - Flutter - - tencent_kit/vendor (= 3.1.0) - - tencent_kit/vendor (3.1.0): + - tencent_kit/vendor (= 4.0.0) + - tencent_kit/vendor (4.0.0): - Flutter DEPENDENCIES: - Flutter (from `Flutter`) - - path_provider (from `.symlinks/plugins/path_provider/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - tencent_kit (from `.symlinks/plugins/tencent_kit/ios`) @@ -27,8 +27,8 @@ SPEC REPOS: EXTERNAL SOURCES: Flutter: :path: Flutter - path_provider: - :path: ".symlinks/plugins/path_provider/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" sqflite: :path: ".symlinks/plugins/sqflite/ios" tencent_kit: @@ -37,9 +37,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 - tencent_kit: 430a6d2980a5c07fef3ce4671025f92e0c575d29 + tencent_kit: 9db7aefcc6dd501bfa258b3d385cf4422701b9cd PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index c28564b..9bfa451 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - A47B4E2D2788685E8EC83B05 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E550C709F5BE86F04F5B1E81 /* libPods-Runner.a */; }; + A6615287E8BD6BA6D4AE1EBE /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E5762F657D7B04C64ACF0DB /* libPods-Runner.a */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -34,10 +34,11 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 53A10B2DDA9A7FDE61260A2F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 56A441886BA7D00789B81833 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 7E5762F657D7B04C64ACF0DB /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -46,9 +47,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9DFC57B207F1D38FE813698A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - E550C709F5BE86F04F5B1E81 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - E87D3240E5D4E8343B925839 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D2AE0A0966226C328A4CC959 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F7BFE312BA992C4AD37E1D1C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -56,13 +56,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A47B4E2D2788685E8EC83B05 /* libPods-Runner.a in Frameworks */, + A6615287E8BD6BA6D4AE1EBE /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 251E60BE95A3A323CC8D7115 /* Pods */ = { + isa = PBXGroup; + children = ( + D2AE0A0966226C328A4CC959 /* Pods-Runner.debug.xcconfig */, + 56A441886BA7D00789B81833 /* Pods-Runner.release.xcconfig */, + F7BFE312BA992C4AD37E1D1C /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 507FBD31C3A53172D6239896 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7E5762F657D7B04C64ACF0DB /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -80,8 +99,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - CE8D8412E01C39B4EF41A68B /* Pods */, - D66298A71A1FFA013550393B /* Frameworks */, + 251E60BE95A3A323CC8D7115 /* Pods */, + 507FBD31C3A53172D6239896 /* Frameworks */, ); sourceTree = ""; }; @@ -117,24 +136,6 @@ name = "Supporting Files"; sourceTree = ""; }; - CE8D8412E01C39B4EF41A68B /* Pods */ = { - isa = PBXGroup; - children = ( - 53A10B2DDA9A7FDE61260A2F /* Pods-Runner.debug.xcconfig */, - E87D3240E5D4E8343B925839 /* Pods-Runner.release.xcconfig */, - 9DFC57B207F1D38FE813698A /* Pods-Runner.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - D66298A71A1FFA013550393B /* Frameworks */ = { - isa = PBXGroup; - children = ( - E550C709F5BE86F04F5B1E81 /* libPods-Runner.a */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -142,7 +143,7 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 052B95C45234CE56B9E3CD76 /* [CP] Check Pods Manifest.lock */, + 033F50648A25B66BDFFF058D /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, @@ -206,7 +207,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 052B95C45234CE56B9E3CD76 /* [CP] Check Pods Manifest.lock */ = { + 033F50648A25B66BDFFF058D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -347,20 +348,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.tencentKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; @@ -478,20 +472,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.tencentKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; @@ -504,20 +491,13 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Flutter", - ); PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.tencentKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner/Runner.entitlements b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 76% rename from example/ios/Runner/Runner.entitlements rename to example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index 0c67376..f9b0d7c 100644 --- a/example/ios/Runner/Runner.entitlements +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -1,5 +1,8 @@ - + + PreviewsEnabled + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 3db53b6..c87d15a 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index e9fed6c..5a7d07b 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -4,6 +4,8 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Tencent Kit CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -137,5 +139,7 @@ UIViewControllerBasedStatusBarAppearance + CADisableMinimumFrameDurationOnPhone + diff --git a/example/lib/model/tencent_api_resp.dart b/example/lib/api/model/tencent_api_resp.dart similarity index 100% rename from example/lib/model/tencent_api_resp.dart rename to example/lib/api/model/tencent_api_resp.dart diff --git a/example/lib/model/tencent_api_resp.g.dart b/example/lib/api/model/tencent_api_resp.g.dart similarity index 100% rename from example/lib/model/tencent_api_resp.g.dart rename to example/lib/api/model/tencent_api_resp.g.dart diff --git a/example/lib/model/tencent_unionid_resp.dart b/example/lib/api/model/tencent_unionid_resp.dart similarity index 100% rename from example/lib/model/tencent_unionid_resp.dart rename to example/lib/api/model/tencent_unionid_resp.dart diff --git a/example/lib/model/tencent_unionid_resp.g.dart b/example/lib/api/model/tencent_unionid_resp.g.dart similarity index 100% rename from example/lib/model/tencent_unionid_resp.g.dart rename to example/lib/api/model/tencent_unionid_resp.g.dart diff --git a/example/lib/api/tencent_api.dart b/example/lib/api/tencent_api.dart new file mode 100644 index 0000000..a91b394 --- /dev/null +++ b/example/lib/api/tencent_api.dart @@ -0,0 +1,57 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:tencent_kit_example/api/model/tencent_api_resp.dart'; +import 'package:tencent_kit_example/api/model/tencent_unionid_resp.dart'; + +class TencentApi { + TencentApi._(); + + /// 用户信息 + /// https://wiki.connect.qq.com/get_user_info + static Future getUserInfo({ + required String appId, + required String openid, + required String accessToken, + }) { + return HttpClient().getUrl(Uri.parse('https://graph.qq.com/user/get_user_info?access_token=$accessToken&oauth_consumer_key=$appId&openid=$openid')).then((HttpClientRequest request) { + return request.close(); + }).then((HttpClientResponse response) async { + if (response.statusCode == HttpStatus.ok) { + final ContentType? contentType = response.headers.contentType; + final Encoding encoding = Encoding.getByName(contentType?.charset) ?? utf8; + final String content = await encoding.decodeStream(response); + return TencentUserInfoResp.fromJson(json.decode(content) as Map); + } + throw HttpException('HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); + }); + } + + /// UnionID + /// https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D + static Future getUnionId({ + required String accessToken, + String unionid = '1', + }) { + return HttpClient().getUrl(Uri.parse('https://graph.qq.com/oauth2.0/me?access_token=$accessToken&unionid=$unionid')).then((HttpClientRequest request) { + return request.close(); + }).then((HttpClientResponse response) async { + if (response.statusCode == HttpStatus.ok) { + final ContentType? contentType = response.headers.contentType; + final Encoding encoding = Encoding.getByName(contentType?.charset) ?? utf8; + final String callback = await encoding.decodeStream(response); + // 腾讯有毒 callback( $json ); + final RegExp exp = RegExp(r'callback\( (.*) \)\;'); + final Match? match = exp.firstMatch(callback); + if (match?.groupCount == 1) { + final String? content = match!.group(1); + if (content != null) { + return TencentUnionidResp.fromJson(json.decode(content) as Map); + } + } + } + throw HttpException('HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); + }); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 3bb46ac..031279f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -4,19 +4,19 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:tencent_kit/tencent_kit.dart'; -import 'package:tencent_kit_example/model/tencent_api_resp.dart'; -import 'package:tencent_kit_example/model/tencent_unionid_resp.dart'; -import 'package:tencent_kit_example/tencent.dart'; +import 'package:tencent_kit_example/api/model/tencent_api_resp.dart'; +import 'package:tencent_kit_example/api/model/tencent_unionid_resp.dart'; +import 'package:tencent_kit_example/api/tencent_api.dart'; const String _TENCENT_APPID = 'your tencent appId'; void main() { - WidgetsFlutterBinding.ensureInitialized(); - Tencent.instance.registerApp(appId: _TENCENT_APPID); runApp(MyApp()); } class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return MaterialApp( @@ -26,6 +26,8 @@ class MyApp extends StatelessWidget { } class Home extends StatefulWidget { + const Home({Key? key}) : super(key: key); + @override State createState() { return _HomeState(); @@ -40,7 +42,7 @@ class _HomeState extends State { @override void initState() { super.initState(); - _respSubs = Tencent.instance.respStream().listen(_listenLogin); + _respSubs = Tencent.respStream().listen(_listenLogin); } void _listenLogin(BaseResp resp) { @@ -64,47 +66,50 @@ class _HomeState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Tencent Kit Demo'), + title: Text('Tencent Kit Demo'), ), body: ListView( children: [ ListTile( - title: const Text('环境检查'), + title: Text('注册APP'), onTap: () async { - final String content = - 'QQ install: ${await Tencent.instance.isQQInstalled()}\nTIM install: ${await Tencent.instance.isTIMInstalled()}'; + await Tencent.registerApp(appId: _TENCENT_APPID); + _showTips('注册APP', '注册成功'); + }, + ), + ListTile( + title: Text('环境检查'), + onTap: () async { + final String content = 'QQ install: ${await Tencent.isQQInstalled()}\nTIM install: ${await Tencent.isTIMInstalled()}'; _showTips('环境检查', content); }, ), ListTile( - title: const Text('3.1.0 之后的版本请先获取权限'), + title: Text('3.1.0 之后的版本请先获取权限'), onTap: () async { - await Tencent.instance.setIsPermissionGranted(granted: true); + await Tencent.setIsPermissionGranted(granted: true); _showTips('授权', '已授权获取设备信息/同意隐私协议'); }, ), ListTile( - title: const Text('登录'), + title: Text('登录'), onTap: () { - Tencent.instance.login( + Tencent.login( scope: [TencentScope.GET_SIMPLE_USERINFO], ); }, ), ListTile( - title: const Text('获取用户信息'), + title: Text('获取用户信息'), onTap: () async { - if ((_loginResp?.isSuccessful ?? false) && - !(_loginResp!.isExpired ?? true)) { - final TencentUserInfoResp userInfo = - await Tencent.instance.getUserInfo( + if ((_loginResp?.isSuccessful ?? false) && !(_loginResp!.isExpired ?? true)) { + final TencentUserInfoResp userInfo = await TencentApi.getUserInfo( appId: _TENCENT_APPID, openid: _loginResp!.openid!, accessToken: _loginResp!.accessToken!, ); if (userInfo.isSuccessful) { - _showTips('用户信息', - '${userInfo.nickname} - ${userInfo.gender} - ${userInfo.genderType}'); + _showTips('用户信息', '${userInfo.nickname} - ${userInfo.gender} - ${userInfo.genderType}'); } else { _showTips('用户信息', '${userInfo.ret} - ${userInfo.msg}'); } @@ -112,57 +117,52 @@ class _HomeState extends State { }, ), ListTile( - title: const Text('获取UnionID'), + title: Text('获取UnionID'), onTap: () async { - if ((_loginResp?.isSuccessful ?? false) && - !(_loginResp!.isExpired ?? true)) { - final TencentUnionidResp unionid = - await Tencent.instance.getUnionId( + if ((_loginResp?.isSuccessful ?? false) && !(_loginResp!.isExpired ?? true)) { + final TencentUnionidResp unionid = await TencentApi.getUnionId( accessToken: _loginResp!.accessToken!, ); if (unionid.isSuccessful) { - _showTips('UnionID', - '${unionid.clientId} - ${unionid.openid} - ${unionid.unionid}'); + _showTips('UnionID', '${unionid.clientId} - ${unionid.openid} - ${unionid.unionid}'); } else { - _showTips('UnionID', - '${unionid.error} - ${unionid.errorDescription}'); + _showTips('UnionID', '${unionid.error} - ${unionid.errorDescription}'); } } }, ), ListTile( - title: const Text('分享说说'), + title: Text('分享说说'), onTap: () { - Tencent.instance.shareMood( + Tencent.shareMood( scene: TencentScene.SCENE_QZONE, summary: '分享测试', ); }, ), ListTile( - title: const Text('文本分享'), + title: Text('文本分享'), onTap: () { - Tencent.instance.shareText( + Tencent.shareText( scene: TencentScene.SCENE_QQ, summary: '分享测试', ); }, ), ListTile( - title: const Text('图片分享'), + title: Text('图片分享'), onTap: () async { - final File file = await DefaultCacheManager().getSingleFile( - 'https://www.baidu.com/img/bd_logo1.png?where=super'); - await Tencent.instance.shareImage( + final File file = await DefaultCacheManager().getSingleFile('https://www.baidu.com/img/bd_logo1.png?where=super'); + await Tencent.shareImage( scene: TencentScene.SCENE_QQ, imageUri: Uri.file(file.path), ); }, ), ListTile( - title: const Text('网页分享'), + title: Text('网页分享'), onTap: () { - Tencent.instance.shareWebpage( + Tencent.shareWebpage( scene: TencentScene.SCENE_QQ, title: 'title', targetUrl: 'https://www.baidu.com/', diff --git a/example/lib/tencent.dart b/example/lib/tencent.dart deleted file mode 100644 index bb619a8..0000000 --- a/example/lib/tencent.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:tencent_kit/tencent_kit.dart'; -import 'package:tencent_kit_example/model/tencent_api_resp.dart'; -import 'package:tencent_kit_example/model/tencent_unionid_resp.dart'; - -extension MixerTencent on Tencent { - /// 用户信息 - /// https://wiki.connect.qq.com/get_user_info - Future getUserInfo({ - required String appId, - required String openid, - required String accessToken, - }) { - return HttpClient() - .getUrl(Uri.parse( - 'https://graph.qq.com/user/get_user_info?access_token=$accessToken&oauth_consumer_key=$appId&openid=$openid')) - .then((HttpClientRequest request) { - return request.close(); - }).then((HttpClientResponse response) async { - if (response.statusCode == HttpStatus.ok) { - final ContentType? contentType = response.headers.contentType; - final Encoding encoding = - Encoding.getByName(contentType?.charset) ?? utf8; - final String content = await encoding.decodeStream(response); - return TencentUserInfoResp.fromJson( - json.decode(content) as Map); - } - throw HttpException( - 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); - }); - } - - /// UnionID - /// https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D - Future getUnionId({ - required String accessToken, - String unionid = '1', - }) { - return HttpClient() - .getUrl(Uri.parse( - 'https://graph.qq.com/oauth2.0/me?access_token=$accessToken&unionid=$unionid')) - .then((HttpClientRequest request) { - return request.close(); - }).then((HttpClientResponse response) async { - if (response.statusCode == HttpStatus.ok) { - final ContentType? contentType = response.headers.contentType; - final Encoding encoding = - Encoding.getByName(contentType?.charset) ?? utf8; - final String callback = await encoding.decodeStream(response); - // 腾讯有毒 callback( $json ); - final RegExp exp = RegExp(r'callback\( (.*) \)\;'); - final Match? match = exp.firstMatch(callback); - if (match?.groupCount == 1) { - final String? content = match!.group(1); - if (content != null) { - return TencentUnionidResp.fromJson( - json.decode(content) as Map); - } - } - } - throw HttpException( - 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); - }); - } -} diff --git a/example/pubspec.lock b/example/pubspec.lock index 0aebfca..e8f3f64 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,198 +5,191 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "22.0.0" + version: "39.0.0" analyzer: dependency: transitive description: name: analyzer - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.7.2" + version: "4.0.0" args: dependency: transitive description: name: args - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.1" async: dependency: transitive description: name: async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.8.2" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" build: dependency: transitive description: name: build - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.3.0" build_config: dependency: transitive description: name: build_config - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.4.7" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.8" build_runner: dependency: "direct dev" description: name: build_runner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.12.2" + version: "2.1.10" build_runner_core: dependency: transitive description: name: build_runner_core - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "6.1.12" + version: "7.2.3" built_collection: dependency: transitive description: name: built_collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "5.1.0" + version: "5.1.1" built_value: dependency: transitive description: name: built_value - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "8.1.1" + version: "8.3.0" characters: dependency: transitive description: name: characters - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" charcode: dependency: transitive description: name: charcode - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.3.1" checked_yaml: dependency: transitive description: name: checked_yaml - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.3" clock: dependency: transitive description: name: clock - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" code_builder: dependency: transitive description: name: code_builder - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "4.1.0" collection: dependency: transitive description: name: collection - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: name: convert - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.0.1" crypto: dependency: transitive description: name: crypto - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.2" + version: "1.0.4" dart_style: dependency: transitive description: name: dart_style - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.14" + version: "2.2.3" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: name: ffi - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.2.1" file: dependency: transitive description: name: file - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "6.1.0" + version: "6.1.2" fixnum: dependency: transitive description: name: fixnum - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -206,229 +199,264 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.3.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" glob: dependency: transitive description: name: glob - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.2" graphs: dependency: transitive description: name: graphs - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "2.1.0" http: dependency: transitive description: name: http - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.13.0" + version: "0.13.4" http_multi_server: dependency: transitive description: name: http_multi_server - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.0" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "4.0.0" io: dependency: transitive description: name: io - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.3" js: dependency: transitive description: name: js - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: "direct main" description: name: json_annotation - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.5.0" json_serializable: dependency: "direct dev" description: name: json_serializable - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "4.0.3" + version: "6.2.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" logging: dependency: transitive description: name: logging - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" matcher: dependency: transitive description: name: matcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "0.12.11" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: name: meta - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.7.0" mime: dependency: transitive description: name: mime - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" package_config: dependency: transitive description: name: package_config - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.2" path: dependency: transitive description: name: path - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_provider: dependency: transitive description: name: path_provider - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.10" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.14" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9" path_provider_linux: dependency: transitive description: name: path_provider_linux - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.6" path_provider_macos: dependency: transitive description: name: path_provider_macos - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.6" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.0.6" pedantic: - dependency: "direct dev" + dependency: transitive description: name: pedantic - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.11.0" + version: "1.11.1" platform: dependency: transitive description: name: platform - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.2" pool: dependency: transitive description: name: pool - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.5.0" process: dependency: transitive description: name: process - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "4.1.0" + version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.2.0" rxdart: dependency: transitive description: name: rxdart - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.26.0" + version: "0.27.3" shelf: dependency: transitive description: name: shelf - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.1" sky_engine: @@ -440,149 +468,156 @@ packages: dependency: transitive description: name: source_gen - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+4" + version: "1.2.2" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2" source_span: dependency: transitive description: name: source_span - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" sqflite: dependency: transitive description: name: sqflite - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0+3" + version: "2.0.2+1" sqflite_common: dependency: transitive description: name: sqflite_common - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.0+2" + version: "2.2.1+1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.1.0" stream_transform: dependency: transitive description: name: stream_transform - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "2.0.0" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.1.0" synchronized: dependency: transitive description: name: synchronized - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.0+2" tencent_kit: dependency: "direct main" description: path: ".." relative: true source: path - version: "3.1.0" + version: "4.0.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.2.0" test_api: dependency: transitive description: name: test_api - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" timing: dependency: transitive description: name: timing - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted version: "1.0.0" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" uuid: dependency: transitive description: name: uuid - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" watcher: dependency: transitive description: name: watcher - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" win32: dependency: transitive description: name: win32 - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.6.1" xdg_directories: dependency: transitive description: name: xdg_directories - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.0+1" yaml: dependency: transitive description: name: yaml - url: "https://pub.flutter-io.cn" + url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.24.0-10" + dart: ">=2.17.0 <3.0.0" + flutter: ">=2.8.1" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1659de1..fcefbd7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -2,14 +2,20 @@ name: tencent_kit_example description: Demonstrates how to use the tencent_kit plugin. # The following line prevents the package from being accidentally published to -# pub.dev using `pub publish`. This is preferred for private packages. +# pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+100 environment: - sdk: ">=2.12.0 <3.0.0" + sdk: ">=2.17.0 <3.0.0" +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter @@ -19,7 +25,7 @@ dependencies: # tencent_kit: ^x.y.z # See https://dart.dev/tools/pub/dependencies#version-constraints # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. + # the parent directory to use the current plugin's version. path: ../ # The following adds the Cupertino Icons font to your application. @@ -28,13 +34,18 @@ dependencies: flutter_cache_manager: ^3.0.0 - json_annotation: ^4.0.0 + json_annotation: ^4.5.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^2.0.0 build_runner: json_serializable: @@ -42,7 +53,7 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter. +# The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is @@ -56,7 +67,7 @@ flutter: # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. + # https://flutter.dev/assets-and-images/#resolution-aware # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 570e0e4..a26a49d 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -1,8 +1,27 @@ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll +// utility in the flutter_test package. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -void main() {} +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:tencent_kit_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data!.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/ios/.gitignore b/ios/.gitignore index aa479fd..0c88507 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -34,4 +34,5 @@ Icon? .tags* /Flutter/Generated.xcconfig +/Flutter/ephemeral/ /Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Classes/TencentKitPlugin.h b/ios/Classes/TencentKitPlugin.h index 08c7572..f33aa5a 100644 --- a/ios/Classes/TencentKitPlugin.h +++ b/ios/Classes/TencentKitPlugin.h @@ -1,4 +1,4 @@ #import -@interface TencentKitPlugin : NSObject +@interface TencentKitPlugin : NSObject @end diff --git a/ios/Classes/TencentKitPlugin.m b/ios/Classes/TencentKitPlugin.m index c24562f..104cb86 100644 --- a/ios/Classes/TencentKitPlugin.m +++ b/ios/Classes/TencentKitPlugin.m @@ -36,43 +36,6 @@ enum TencentRetCode { [registrar addMethodCallDelegate:instance channel:channel]; } -static NSString *const METHOD_REGISTERAPP = @"registerApp"; -static NSString *const METHOD_ISQQINSTALLED = @"isQQInstalled"; -static NSString *const METHOD_ISTIMINSTALLED = @"isTIMInstalled"; -static NSString *const METHOD_LOGIN = @"login"; -static NSString *const METHOD_LOGOUT = @"logout"; -static NSString *const METHOD_SHAREMOOD = @"shareMood"; -static NSString *const METHOD_SHARETEXT = @"shareText"; -static NSString *const METHOD_SHAREIMAGE = @"shareImage"; -static NSString *const METHOD_SHAREMUSIC = @"shareMusic"; -static NSString *const METHOD_SHAREWEBPAGE = @"shareWebpage"; - -static NSString *const METHOD_ONLOGINRESP = @"onLoginResp"; -static NSString *const METHOD_ONSHARERESP = @"onShareResp"; - -static NSString *const ARGUMENT_KEY_APPID = @"appId"; -static NSString *const ARGUMENT_KEY_UNIVERSALLINK = @"universalLink"; -static NSString *const ARGUMENT_KEY_SCOPE = @"scope"; -static NSString *const ARGUMENT_KEY_SCENE = @"scene"; -static NSString *const ARGUMENT_KEY_TITLE = @"title"; -static NSString *const ARGUMENT_KEY_SUMMARY = @"summary"; -static NSString *const ARGUMENT_KEY_IMAGEURI = @"imageUri"; -static NSString *const ARGUMENT_KEY_IMAGEURIS = @"imageUris"; -static NSString *const ARGUMENT_KEY_VIDEOURI = @"videoUri"; -static NSString *const ARGUMENT_KEY_MUSICURL = @"musicUrl"; -static NSString *const ARGUMENT_KEY_TARGETURL = @"targetUrl"; -static NSString *const ARGUMENT_KEY_APPNAME = @"appName"; -static NSString *const ARGUMENT_KEY_EXTINT = @"extInt"; - -static NSString *const ARGUMENT_KEY_RESULT_RET = @"ret"; -static NSString *const ARGUMENT_KEY_RESULT_MSG = @"msg"; -static NSString *const ARGUMENT_KEY_RESULT_OPENID = @"openid"; -static NSString *const ARGUMENT_KEY_RESULT_ACCESS_TOKEN = @"access_token"; -static NSString *const ARGUMENT_KEY_RESULT_EXPIRES_IN = @"expires_in"; -static NSString *const ARGUMENT_KEY_RESULT_CREATE_AT = @"create_at"; - -static NSString *const SCHEME_FILE = @"file"; - - (instancetype)initWithChannel:(FlutterMethodChannel *)channel { self = [super init]; if (self) { @@ -87,9 +50,9 @@ static NSString *const SCHEME_FILE = @"file"; NSNumber *granted = call.arguments[@"granted"]; [TencentOAuth setIsUserAgreedAuthorization: [granted boolValue]]; result(nil); - } else if ([METHOD_REGISTERAPP isEqualToString:call.method]) { - NSString *appId = call.arguments[ARGUMENT_KEY_APPID]; - NSString *universalLink = call.arguments[ARGUMENT_KEY_UNIVERSALLINK]; + } else if ([@"registerApp" isEqualToString:call.method]) { + NSString *appId = call.arguments[@"appId"]; + NSString *universalLink = call.arguments[@"universalLink"]; if (universalLink != nil) { _oauth = [[TencentOAuth alloc] initWithAppId:appId andUniversalLink:universalLink @@ -98,23 +61,23 @@ static NSString *const SCHEME_FILE = @"file"; _oauth = [[TencentOAuth alloc] initWithAppId:appId andDelegate:self]; } result(nil); - } else if ([METHOD_ISQQINSTALLED isEqualToString:call.method]) { + } else if ([@"isQQInstalled" isEqualToString:call.method]) { result([NSNumber numberWithBool:[TencentOAuth iphoneQQInstalled]]); - } else if ([METHOD_ISTIMINSTALLED isEqualToString:call.method]) { + } else if ([@"isTIMInstalled" isEqualToString:call.method]) { result([NSNumber numberWithBool:[TencentOAuth iphoneTIMInstalled]]); - } else if ([METHOD_LOGIN isEqualToString:call.method]) { + } else if ([@"login" isEqualToString:call.method]) { [self login:call result:result]; - } else if ([METHOD_LOGOUT isEqualToString:call.method]) { + } else if ([@"logout" isEqualToString:call.method]) { [self logout:call result:result]; - } else if ([METHOD_SHAREMOOD isEqualToString:call.method]) { + } else if ([@"shareMood" isEqualToString:call.method]) { [self shareMood:call result:result]; - } else if ([METHOD_SHARETEXT isEqualToString:call.method]) { + } else if ([@"shareText" isEqualToString:call.method]) { [self shareText:call result:result]; - } else if ([METHOD_SHAREIMAGE isEqualToString:call.method]) { + } else if ([@"shareImage" isEqualToString:call.method]) { [self shareImage:call result:result]; - } else if ([METHOD_SHAREMUSIC isEqualToString:call.method]) { + } else if ([@"shareMusic" isEqualToString:call.method]) { [self shareMusic:call result:result]; - } else if ([METHOD_SHAREWEBPAGE isEqualToString:call.method]) { + } else if ([@"shareWebpage" isEqualToString:call.method]) { [self shareWebpage:call result:result]; } else { result(FlutterMethodNotImplemented); @@ -123,7 +86,7 @@ static NSString *const SCHEME_FILE = @"file"; - (void)login:(FlutterMethodCall *)call result:(FlutterResult)result { if (_oauth != nil) { - NSString *scope = call.arguments[ARGUMENT_KEY_SCOPE]; + NSString *scope = call.arguments[@"scope"]; NSArray *permissions = [scope componentsSeparatedByString:@","]; [_oauth authorize:permissions]; } @@ -138,11 +101,11 @@ static NSString *const SCHEME_FILE = @"file"; } - (void)shareMood:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[ARGUMENT_KEY_SCENE]; + NSNumber *scene = call.arguments[@"scene"]; if (scene.intValue == SCENE_QZONE) { - NSString *summary = call.arguments[ARGUMENT_KEY_SUMMARY]; - NSArray *imageUris = call.arguments[ARGUMENT_KEY_IMAGEURIS]; - NSString *videoUri = call.arguments[ARGUMENT_KEY_VIDEOURI]; + NSString *summary = call.arguments[@"summary"]; + NSArray *imageUris = call.arguments[@"imageUris"]; + NSString *videoUri = call.arguments[@"videoUri"]; if (videoUri == nil || videoUri.length == 0) { NSMutableArray *imageDatas = [NSMutableArray array]; @@ -172,9 +135,9 @@ static NSString *const SCHEME_FILE = @"file"; } - (void)shareText:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[ARGUMENT_KEY_SCENE]; + NSNumber *scene = call.arguments[@"scene"]; if (scene.intValue == SCENE_QQ) { - NSString *summary = call.arguments[ARGUMENT_KEY_SUMMARY]; + NSString *summary = call.arguments[@"summary"]; QQApiTextObject *object = [QQApiTextObject objectWithText:summary]; SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:object]; [QQApiInterface sendReq:req]; @@ -183,11 +146,11 @@ static NSString *const SCHEME_FILE = @"file"; } - (void)shareImage:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[ARGUMENT_KEY_SCENE]; + NSNumber *scene = call.arguments[@"scene"]; if (scene.intValue == SCENE_QQ) { - NSString *imageUri = call.arguments[ARGUMENT_KEY_IMAGEURI]; - // NSString *appName = call.arguments[ARGUMENT_KEY_APPNAME]; - // NSNumber *extInt = call.arguments[ARGUMENT_KEY_EXTINT]; + NSString *imageUri = call.arguments[@"imageUri"]; + // NSString *appName = call.arguments[@"appName"]; + // NSNumber *extInt = call.arguments[@"extInt"]; NSURL *imageUrl = [NSURL URLWithString:imageUri]; NSData *imageData = [NSData dataWithContentsOfFile:imageUrl.path]; @@ -202,18 +165,18 @@ static NSString *const SCHEME_FILE = @"file"; } - (void)shareMusic:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[ARGUMENT_KEY_SCENE]; - NSString *title = call.arguments[ARGUMENT_KEY_TITLE]; - NSString *summary = call.arguments[ARGUMENT_KEY_SUMMARY]; - NSString *imageUri = call.arguments[ARGUMENT_KEY_IMAGEURI]; - NSString *musicUrl = call.arguments[ARGUMENT_KEY_MUSICURL]; - NSString *targetUrl = call.arguments[ARGUMENT_KEY_TARGETURL]; - // NSString *appName = call.arguments[ARGUMENT_KEY_APPNAME]; - // NSNumber *extInt = call.arguments[ARGUMENT_KEY_EXTINT]; + NSNumber *scene = call.arguments[@"scene"]; + NSString *title = call.arguments[@"title"]; + NSString *summary = call.arguments[@"summary"]; + NSString *imageUri = call.arguments[@"imageUri"]; + NSString *musicUrl = call.arguments[@"musicUrl"]; + NSString *targetUrl = call.arguments[@"targetUrl"]; + // NSString *appName = call.arguments[@"appName"]; + // NSNumber *extInt = call.arguments[@"extInt"]; if (scene.intValue == SCENE_QQ) { QQApiAudioObject *object = nil; NSURL *imageUrl = [NSURL URLWithString:imageUri]; - if ([SCHEME_FILE isEqualToString:imageUrl.scheme]) { + if ([@"file" isEqualToString:imageUrl.scheme]) { NSData *imageData = [NSData dataWithContentsOfFile:imageUrl.path]; object = [QQApiAudioObject objectWithURL:[NSURL URLWithString:targetUrl] title:title @@ -233,17 +196,17 @@ static NSString *const SCHEME_FILE = @"file"; } - (void)shareWebpage:(FlutterMethodCall *)call result:(FlutterResult)result { - NSNumber *scene = call.arguments[ARGUMENT_KEY_SCENE]; - NSString *title = call.arguments[ARGUMENT_KEY_TITLE]; - NSString *summary = call.arguments[ARGUMENT_KEY_SUMMARY]; - NSString *imageUri = call.arguments[ARGUMENT_KEY_IMAGEURI]; - NSString *targetUrl = call.arguments[ARGUMENT_KEY_TARGETURL]; - // NSString *appName = call.arguments[ARGUMENT_KEY_APPNAME]; - // NSNumber *extInt = call.arguments[ARGUMENT_KEY_EXTINT]; + NSNumber *scene = call.arguments[@"scene"]; + NSString *title = call.arguments[@"title"]; + NSString *summary = call.arguments[@"summary"]; + NSString *imageUri = call.arguments[@"imageUri"]; + NSString *targetUrl = call.arguments[@"targetUrl"]; + // NSString *appName = call.arguments[@"appName"]; + // NSNumber *extInt = call.arguments[@"extInt"]; QQApiNewsObject *object = nil; NSURL *imageUrl = [NSURL URLWithString:imageUri]; - if ([SCHEME_FILE isEqualToString:imageUrl.scheme]) { + if ([@"file" isEqualToString:imageUrl.scheme]) { NSData *imageData = [NSData dataWithContentsOfFile:imageUrl.path]; object = [QQApiNewsObject objectWithURL:[NSURL URLWithString:targetUrl] title:title @@ -319,19 +282,19 @@ static NSString *const SCHEME_FILE = @"file"; ceil(_oauth.expirationDate.timeIntervalSinceNow); // 向上取整 long long createAt = [[NSDate date] timeIntervalSince1970] * 1000.0; [dictionary setValue:[NSNumber numberWithInt:RET_SUCCESS] - forKey:ARGUMENT_KEY_RESULT_RET]; - [dictionary setValue:openId forKey:ARGUMENT_KEY_RESULT_OPENID]; - [dictionary setValue:accessToken forKey:ARGUMENT_KEY_RESULT_ACCESS_TOKEN]; + forKey:@"ret"]; + [dictionary setValue:openId forKey:@"openid"]; + [dictionary setValue:accessToken forKey:@"access_token"]; [dictionary setValue:[NSNumber numberWithLongLong:expiresIn] - forKey:ARGUMENT_KEY_RESULT_EXPIRES_IN]; + forKey:@"expires_in"]; [dictionary setValue:[NSNumber numberWithLongLong:createAt] - forKey:ARGUMENT_KEY_RESULT_CREATE_AT]; + forKey:@"create_at"]; } else { // 登录失败 [dictionary setValue:[NSNumber numberWithInt:RET_COMMON] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; } - [_channel invokeMethod:METHOD_ONLOGINRESP arguments:dictionary]; + [_channel invokeMethod:@"onLoginResp" arguments:dictionary]; } - (void)tencentDidNotLogin:(BOOL)cancelled { @@ -339,21 +302,21 @@ static NSString *const SCHEME_FILE = @"file"; if (cancelled) { // 取消登录 [dictionary setValue:[NSNumber numberWithInt:RET_USERCANCEL] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; } else { // 登录失败 [dictionary setValue:[NSNumber numberWithInt:RET_COMMON] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; } - [_channel invokeMethod:METHOD_ONLOGINRESP arguments:dictionary]; + [_channel invokeMethod:@"onLoginResp" arguments:dictionary]; } - (void)tencentDidNotNetWork { // 登录失败 NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; [dictionary setValue:[NSNumber numberWithInt:RET_COMMON] - forKey:ARGUMENT_KEY_RESULT_RET]; - [_channel invokeMethod:METHOD_ONLOGINRESP arguments:dictionary]; + forKey:@"ret"]; + [_channel invokeMethod:@"onLoginResp" arguments:dictionary]; } #pragma mark - QQApiInterfaceDelegate @@ -368,23 +331,23 @@ static NSString *const SCHEME_FILE = @"file"; case 0: // 分享成功 [dictionary setValue:[NSNumber numberWithInt:RET_SUCCESS] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; break; case -4: // 用户取消 [dictionary setValue:[NSNumber numberWithInt:RET_USERCANCEL] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; break; default: [dictionary setValue:[NSNumber numberWithInt:RET_COMMON] - forKey:ARGUMENT_KEY_RESULT_RET]; + forKey:@"ret"]; NSString *errorMsg = [NSString stringWithFormat:@"result: %@, description: %@.", resp.result, resp.errorDescription]; - [dictionary setValue:errorMsg forKey:ARGUMENT_KEY_RESULT_MSG]; + [dictionary setValue:errorMsg forKey:@"msg"]; break; } - [_channel invokeMethod:METHOD_ONSHARERESP arguments:dictionary]; + [_channel invokeMethod:@"onShareResp" arguments:dictionary]; } } diff --git a/ios/Libraries/TencentOpenAPI.framework/TencentOpenAPI b/ios/Libraries/TencentOpenAPI.framework/TencentOpenAPI index 56ca89c..7a46969 100644 Binary files a/ios/Libraries/TencentOpenAPI.framework/TencentOpenAPI and b/ios/Libraries/TencentOpenAPI.framework/TencentOpenAPI differ diff --git a/ios/tencent_kit.podspec b/ios/tencent_kit.podspec index f783c28..35e576e 100644 --- a/ios/tencent_kit.podspec +++ b/ios/tencent_kit.podspec @@ -1,10 +1,10 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. -# Run `pod lib lint tencent_kit.podspec' to validate before publishing. +# Run `pod lib lint tencent_kit.podspec` to validate before publishing. # Pod::Spec.new do |s| s.name = 'tencent_kit' - s.version = '3.1.0' + s.version = '4.0.0' s.summary = 'A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs.' s.description = <<-DESC A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs. @@ -16,16 +16,16 @@ A powerful Flutter plugin allowing developers to auth/share with natvie Android s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - s.platform = :ios, '8.0' + s.platform = :ios, '9.0' - # v3.5.10 + # v3.5.11 s.subspec 'vendor' do |sp| sp.vendored_frameworks = 'Libraries/*.framework' sp.frameworks = 'Security', 'SystemConfiguration', 'CoreGraphics', 'CoreTelephony', 'WebKit' sp.libraries = 'iconv', 'sqlite3', 'stdc++', 'z' sp.requires_arc = true end - + # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } end diff --git a/lib/src/tencent.dart b/lib/src/tencent.dart index 471256c..b9dcf60 100644 --- a/lib/src/tencent.dart +++ b/lib/src/tencent.dart @@ -1,192 +1,103 @@ -import 'dart:async'; - -import 'package:flutter/services.dart'; import 'package:tencent_kit/src/model/resp.dart'; import 'package:tencent_kit/src/tencent_constant.dart'; -/// +import 'tencent_kit_platform_interface.dart'; + class Tencent { - /// Tencent._(); - static Tencent get instance => _instance; - - static final Tencent _instance = Tencent._(); - - static const String _METHOD_REGISTERAPP = 'registerApp'; - static const String _METHOD_ISQQINSTALLED = 'isQQInstalled'; - static const String _METHOD_ISTIMINSTALLED = 'isTIMInstalled'; - static const String _METHOD_LOGIN = 'login'; - static const String _METHOD_LOGOUT = 'logout'; - static const String _METHOD_SHAREMOOD = 'shareMood'; - static const String _METHOD_SHARETEXT = 'shareText'; - static const String _METHOD_SHAREIMAGE = 'shareImage'; - static const String _METHOD_SHAREMUSIC = 'shareMusic'; - static const String _METHOD_SHAREWEBPAGE = 'shareWebpage'; - - static const String _METHOD_ONLOGINRESP = 'onLoginResp'; - static const String _METHOD_ONSHARERESP = 'onShareResp'; - - static const String _ARGUMENT_KEY_APPID = 'appId'; - static const String _ARGUMENT_KEY_UNIVERSALLINK = 'universalLink'; - static const String _ARGUMENT_KEY_SCOPE = 'scope'; - static const String _ARGUMENT_KEY_SCENE = 'scene'; - static const String _ARGUMENT_KEY_TITLE = 'title'; - static const String _ARGUMENT_KEY_SUMMARY = 'summary'; - static const String _ARGUMENT_KEY_IMAGEURI = 'imageUri'; - static const String _ARGUMENT_KEY_IMAGEURIS = 'imageUris'; - static const String _ARGUMENT_KEY_VIDEOURI = 'videoUri'; - static const String _ARGUMENT_KEY_MUSICURL = 'musicUrl'; - static const String _ARGUMENT_KEY_TARGETURL = 'targetUrl'; - static const String _ARGUMENT_KEY_APPNAME = 'appName'; - static const String _ARGUMENT_KEY_EXTINT = 'extInt'; - - static const String _SCHEME_FILE = 'file'; - - late final MethodChannel _channel = - const MethodChannel('v7lin.github.io/tencent_kit') - ..setMethodCallHandler(_handleMethod); - - final StreamController _respStreamController = - StreamController.broadcast(); - - Future _handleMethod(MethodCall call) async { - switch (call.method) { - case _METHOD_ONLOGINRESP: - _respStreamController.add(LoginResp.fromJson( - (call.arguments as Map).cast())); - break; - case _METHOD_ONSHARERESP: - _respStreamController.add(ShareMsgResp.fromJson( - (call.arguments as Map).cast())); - break; - } - } - /// 设置是否已授权获取设备信息/是否同意隐私协议 - Future setIsPermissionGranted({ + static Future setIsPermissionGranted({ required bool granted, String? buildModel /* android.os.Build.MODEL */, }) { - return _channel.invokeMethod( - 'setIsPermissionGranted', - { - 'granted': granted, - if (buildModel?.isNotEmpty ?? false) 'build_model': buildModel, - }, + return TencentKitPlatform.instance.setIsPermissionGranted( + granted: granted, + buildModel: buildModel, ); } /// 向 Open_SDK 注册 - Future registerApp({ + static Future registerApp({ required String appId, String? universalLink, }) { - return _channel.invokeMethod( - _METHOD_REGISTERAPP, - { - _ARGUMENT_KEY_APPID: appId, - if (universalLink?.isNotEmpty ?? false) - _ARGUMENT_KEY_UNIVERSALLINK: universalLink, - }, + return TencentKitPlatform.instance.registerApp( + appId: appId, + universalLink: universalLink, ); } + /// 检查QQ是否已安装 + static Future isQQInstalled() { + return TencentKitPlatform.instance.isQQInstalled(); + } + + /// 检查QQ是否已安装 + static Future isTIMInstalled() { + return TencentKitPlatform.instance.isTIMInstalled(); + } + /// - Stream respStream() { - return _respStreamController.stream; - } - - /// 检查QQ是否已安装 - Future isQQInstalled() async { - return await _channel.invokeMethod(_METHOD_ISQQINSTALLED) ?? false; - } - - /// 检查QQ是否已安装 - Future isTIMInstalled() async { - return await _channel.invokeMethod(_METHOD_ISTIMINSTALLED) ?? false; + static Stream respStream() { + return TencentKitPlatform.instance.respStream(); } /// 登录 - Future login({ + static Future login({ required List scope, }) { - return _channel.invokeMethod( - _METHOD_LOGIN, - { - _ARGUMENT_KEY_SCOPE: scope.join(','), - }, - ); + return TencentKitPlatform.instance.login(scope: scope); } /// 登出 - Future logout() { - return _channel.invokeMethod(_METHOD_LOGOUT); + static Future logout() { + return TencentKitPlatform.instance.logout(); } /// 分享 - 说说 - Future shareMood({ + static Future shareMood({ required int scene, String? summary, List? imageUris, Uri? videoUri, }) { - assert(scene == TencentScene.SCENE_QZONE); - assert((summary?.isNotEmpty ?? false) || - ((imageUris?.isNotEmpty ?? false) && - imageUris! - .every((Uri element) => element.isScheme(_SCHEME_FILE))) || - (videoUri != null && videoUri.isScheme(_SCHEME_FILE))); - return _channel.invokeMethod( - _METHOD_SHAREMOOD, - { - _ARGUMENT_KEY_SCENE: scene, - if (summary?.isNotEmpty ?? false) _ARGUMENT_KEY_SUMMARY: summary, - if (imageUris?.isNotEmpty ?? false) - _ARGUMENT_KEY_IMAGEURIS: - imageUris!.map((Uri imageUri) => imageUri.toString()).toList(), - if (videoUri != null) _ARGUMENT_KEY_VIDEOURI: videoUri.toString(), - }, + return TencentKitPlatform.instance.shareMood( + scene: scene, + summary: summary, + imageUris: imageUris, + videoUri: videoUri, ); } /// 分享 - 文本(Android调用的是系统API,故而不会有回调) - Future shareText({ + static Future shareText({ required int scene, required String summary, }) { - assert(scene == TencentScene.SCENE_QQ); - return _channel.invokeMethod( - _METHOD_SHARETEXT, - { - _ARGUMENT_KEY_SCENE: scene, - _ARGUMENT_KEY_SUMMARY: summary, - }, + return TencentKitPlatform.instance.shareText( + scene: scene, + summary: summary, ); } /// 分享 - 图片 - Future shareImage({ + static Future shareImage({ required int scene, required Uri imageUri, String? appName, int extInt = TencentQZoneFlag.DEFAULT, }) { - assert(scene == TencentScene.SCENE_QQ); - assert(imageUri.isScheme(_SCHEME_FILE)); - return _channel.invokeMethod( - _METHOD_SHAREIMAGE, - { - _ARGUMENT_KEY_SCENE: scene, - _ARGUMENT_KEY_IMAGEURI: imageUri.toString(), - if (appName?.isNotEmpty ?? false) _ARGUMENT_KEY_APPNAME: appName, - _ARGUMENT_KEY_EXTINT: extInt, - }, + return TencentKitPlatform.instance.shareImage( + scene: scene, + imageUri: imageUri, + appName: appName, + extInt: extInt, ); } /// 分享 - 音乐 - Future shareMusic({ + static Future shareMusic({ required int scene, required String title, String? summary, @@ -196,24 +107,20 @@ class Tencent { String? appName, int extInt = TencentQZoneFlag.DEFAULT, }) { - assert(scene == TencentScene.SCENE_QQ); - return _channel.invokeMethod( - _METHOD_SHAREMUSIC, - { - _ARGUMENT_KEY_SCENE: scene, - _ARGUMENT_KEY_TITLE: title, - if (summary?.isNotEmpty ?? false) _ARGUMENT_KEY_SUMMARY: summary, - if (imageUri != null) _ARGUMENT_KEY_IMAGEURI: imageUri.toString(), - _ARGUMENT_KEY_MUSICURL: musicUrl, - _ARGUMENT_KEY_TARGETURL: targetUrl, - if (appName?.isNotEmpty ?? false) _ARGUMENT_KEY_APPNAME: appName, - _ARGUMENT_KEY_EXTINT: extInt, - }, + return TencentKitPlatform.instance.shareMusic( + scene: scene, + title: title, + summary: summary, + imageUri: imageUri, + musicUrl: musicUrl, + targetUrl: targetUrl, + appName: appName, + extInt: extInt, ); } /// 分享 - 网页 - Future shareWebpage({ + static Future shareWebpage({ required int scene, required String title, String? summary, @@ -222,17 +129,14 @@ class Tencent { String? appName, int extInt = TencentQZoneFlag.DEFAULT, }) { - return _channel.invokeMethod( - _METHOD_SHAREWEBPAGE, - { - _ARGUMENT_KEY_SCENE: scene, - _ARGUMENT_KEY_TITLE: title, - if (summary?.isNotEmpty ?? false) _ARGUMENT_KEY_SUMMARY: summary, - if (imageUri != null) _ARGUMENT_KEY_IMAGEURI: imageUri.toString(), - _ARGUMENT_KEY_TARGETURL: targetUrl, - if (appName?.isNotEmpty ?? false) _ARGUMENT_KEY_APPNAME: appName, - _ARGUMENT_KEY_EXTINT: extInt, - }, + return TencentKitPlatform.instance.shareWebpage( + scene: scene, + title: title, + summary: summary, + imageUri: imageUri, + targetUrl: targetUrl, + appName: appName, + extInt: extInt, ); } } diff --git a/lib/src/tencent_kit_method_channel.dart b/lib/src/tencent_kit_method_channel.dart new file mode 100644 index 0000000..40dc004 --- /dev/null +++ b/lib/src/tencent_kit_method_channel.dart @@ -0,0 +1,201 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:tencent_kit/src/model/resp.dart'; +import 'package:tencent_kit/src/tencent_constant.dart'; + +import 'tencent_kit_platform_interface.dart'; + +/// An implementation of [TencentKitPlatform] that uses method channels. +class MethodChannelTencentKit extends TencentKitPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + late final MethodChannel methodChannel = const MethodChannel('v7lin.github.io/tencent_kit')..setMethodCallHandler(_handleMethod); + + final StreamController _respStreamController = StreamController.broadcast(); + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case 'onLoginResp': + _respStreamController.add(LoginResp.fromJson((call.arguments as Map).cast())); + break; + case 'onShareResp': + _respStreamController.add(ShareMsgResp.fromJson((call.arguments as Map).cast())); + break; + } + } + + @override + Future setIsPermissionGranted({ + required bool granted, + String? buildModel /* android.os.Build.MODEL */, + }) { + return methodChannel.invokeMethod( + 'setIsPermissionGranted', + { + 'granted': granted, + if (buildModel?.isNotEmpty ?? false) 'build_model': buildModel, + }, + ); + } + + @override + Future registerApp({ + required String appId, + String? universalLink, + }) { + return methodChannel.invokeMethod( + 'registerApp', + { + 'appId': appId, + if (universalLink?.isNotEmpty ?? false) + 'universalLink': universalLink, + }, + ); + } + + @override + Future isQQInstalled() async { + return await methodChannel.invokeMethod('isQQInstalled') ?? false; + } + + @override + Future isTIMInstalled() async { + return await methodChannel.invokeMethod('isTIMInstalled') ?? false; + } + + @override + Stream respStream() { + return _respStreamController.stream; + } + + @override + Future login({ + required List scope, + }) { + return methodChannel.invokeMethod( + 'login', + { + 'scope': scope.join(','), + }, + ); + } + + @override + Future logout() { + return methodChannel.invokeMethod('logout'); + } + + @override + Future shareMood({ + required int scene, + String? summary, + List? imageUris, + Uri? videoUri, + }) { + assert(scene == TencentScene.SCENE_QZONE); + assert((summary?.isNotEmpty ?? false) || + ((imageUris?.isNotEmpty ?? false) && + imageUris! + .every((Uri element) => element.isScheme('file'))) || + (videoUri != null && videoUri.isScheme('file'))); + return methodChannel.invokeMethod( + 'shareMood', + { + 'scene': scene, + if (summary?.isNotEmpty ?? false) 'summary': summary, + if (imageUris?.isNotEmpty ?? false) + 'imageUris': + imageUris!.map((Uri imageUri) => imageUri.toString()).toList(), + if (videoUri != null) 'videoUri': videoUri.toString(), + }, + ); + } + + @override + Future shareText({ + required int scene, + required String summary, + }) { + assert(scene == TencentScene.SCENE_QQ); + return methodChannel.invokeMethod( + 'shareText', + { + 'scene': scene, + 'summary': summary, + }, + ); + } + + @override + Future shareImage({ + required int scene, + required Uri imageUri, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + assert(scene == TencentScene.SCENE_QQ); + assert(imageUri.isScheme('file')); + return methodChannel.invokeMethod( + 'shareImage', + { + 'scene': scene, + 'imageUri': imageUri.toString(), + if (appName?.isNotEmpty ?? false) 'appName': appName, + 'extInt': extInt, + }, + ); + } + + @override + Future shareMusic({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String musicUrl, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + assert(scene == TencentScene.SCENE_QQ); + return methodChannel.invokeMethod( + 'shareMusic', + { + 'scene': scene, + 'title': title, + if (summary?.isNotEmpty ?? false) 'summary': summary, + if (imageUri != null) 'imageUri': imageUri.toString(), + 'musicUrl': musicUrl, + 'targetUrl': targetUrl, + if (appName?.isNotEmpty ?? false) 'appName': appName, + 'extInt': extInt, + }, + ); + } + + @override + Future shareWebpage({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + return methodChannel.invokeMethod( + 'shareWebpage', + { + 'scene': scene, + 'title': title, + if (summary?.isNotEmpty ?? false) 'summary': summary, + if (imageUri != null) 'imageUri': imageUri.toString(), + 'targetUrl': targetUrl, + if (appName?.isNotEmpty ?? false) 'appName': appName, + 'extInt': extInt, + }, + ); + } +} diff --git a/lib/src/tencent_kit_platform_interface.dart b/lib/src/tencent_kit_platform_interface.dart new file mode 100644 index 0000000..ac7b673 --- /dev/null +++ b/lib/src/tencent_kit_platform_interface.dart @@ -0,0 +1,113 @@ +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:tencent_kit/src/model/resp.dart'; +import 'package:tencent_kit/src/tencent_constant.dart'; + +import 'tencent_kit_method_channel.dart'; + +abstract class TencentKitPlatform extends PlatformInterface { + /// Constructs a TencentKitPlatform. + TencentKitPlatform() : super(token: _token); + + static final Object _token = Object(); + + static TencentKitPlatform _instance = MethodChannelTencentKit(); + + /// The default instance of [TencentKitPlatform] to use. + /// + /// Defaults to [MethodChannelTencentKit]. + static TencentKitPlatform get instance => _instance; + + /// Platform-specific implementations should set this with their own + /// platform-specific class that extends [TencentKitPlatform] when + /// they register themselves. + static set instance(TencentKitPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + Future setIsPermissionGranted({ + required bool granted, + String? buildModel /* android.os.Build.MODEL */, + }) { + throw UnimplementedError('setIsPermissionGranted({required granted, buildModel}) has not been implemented.'); + } + + Future registerApp({ + required String appId, + String? universalLink, + }) { + throw UnimplementedError('registerApp({required appId, universalLink}) has not been implemented.'); + } + + Future isQQInstalled() { + throw UnimplementedError('isQQInstalled() has not been implemented.'); + } + + Future isTIMInstalled() { + throw UnimplementedError('isTIMInstalled() has not been implemented.'); + } + + Stream respStream() { + throw UnimplementedError('respStream() has not been implemented.'); + } + + Future login({ + required List scope, + }) { + throw UnimplementedError('login({required scope}) has not been implemented.'); + } + + Future logout() { + throw UnimplementedError('logout() has not been implemented.'); + } + + Future shareMood({ + required int scene, + String? summary, + List? imageUris, + Uri? videoUri, + }) { + throw UnimplementedError('shareMood({required scene, summary, imageUris, videoUri}) has not been implemented.'); + } + + Future shareText({ + required int scene, + required String summary, + }) { + throw UnimplementedError('shareText({required scene, required summary}) has not been implemented.'); + } + + Future shareImage({ + required int scene, + required Uri imageUri, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError('shareImage({required scene, required imageUri, appName, extInt}) has not been implemented.'); + } + + Future shareMusic({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String musicUrl, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError('shareMusic({required scene, required title, summary, imageUri, required musicUrl, required targetUrl, appName, extInt}) has not been implemented.'); + } + + Future shareWebpage({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError('shareWebpage({required scene, required title, summary, imageUri, required targetUrl, appName, extInt}) has not been implemented.'); + } +} diff --git a/pubspec.lock b/pubspec.lock index 33e9740..85f8162 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,21 +7,21 @@ packages: name: _fe_analyzer_shared url: "https://pub.flutter-io.cn" source: hosted - version: "18.0.0" + version: "39.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "4.0.0" args: dependency: transitive description: name: args url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.3.1" async: dependency: transitive description: @@ -42,56 +42,56 @@ packages: name: build url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.3.0" build_config: dependency: transitive description: name: build_config url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.7" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.10" + version: "3.1.0" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.0.8" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.flutter-io.cn" source: hosted - version: "1.12.2" + version: "2.1.10" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.flutter-io.cn" source: hosted - version: "6.1.12" + version: "7.2.3" built_collection: dependency: transitive description: name: built_collection url: "https://pub.flutter-io.cn" source: hosted - version: "5.0.0" + version: "5.1.1" built_value: dependency: transitive description: name: built_value url: "https://pub.flutter-io.cn" source: hosted - version: "8.0.3" + version: "8.3.0" characters: dependency: transitive description: @@ -113,13 +113,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.0" clock: dependency: transitive description: @@ -133,87 +126,101 @@ packages: name: code_builder url: "https://pub.flutter-io.cn" source: hosted - version: "3.7.0" + version: "4.1.0" collection: dependency: transitive description: name: collection url: "https://pub.flutter-io.cn" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: name: convert url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "3.0.1" crypto: dependency: transitive description: name: crypto url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "3.0.2" dart_style: dependency: transitive description: name: dart_style url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.14" + version: "2.2.3" fake_async: dependency: transitive description: name: fake_async url: "https://pub.flutter-io.cn" source: hosted - version: "1.2.0" + version: "1.3.0" file: dependency: transitive description: name: file url: "https://pub.flutter-io.cn" source: hosted - version: "6.1.0" + version: "6.1.2" fixnum: dependency: transitive description: name: fixnum url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.2" glob: dependency: transitive description: name: glob url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.0.2" graphs: dependency: transitive description: name: graphs url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "2.1.0" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "3.2.0" http_parser: dependency: transitive description: @@ -227,35 +234,42 @@ packages: name: io url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.3" js: dependency: transitive description: name: js url: "https://pub.flutter-io.cn" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: "direct main" description: name: json_annotation url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.0" + version: "4.5.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.flutter-io.cn" source: hosted - version: "4.0.3" + version: "6.2.0" + lints: + dependency: transitive + description: + name: lints + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" logging: dependency: transitive description: name: logging url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.2" matcher: dependency: transitive description: @@ -263,6 +277,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.4" meta: dependency: transitive description: @@ -276,28 +297,28 @@ packages: name: mime url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.2" package_config: dependency: transitive description: name: package_config url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.0.2" path: dependency: transitive description: name: path url: "https://pub.flutter-io.cn" source: hosted - version: "1.8.0" - pedantic: - dependency: "direct dev" + version: "1.8.1" + plugin_platform_interface: + dependency: "direct main" description: - name: pedantic + name: plugin_platform_interface url: "https://pub.flutter-io.cn" source: hosted - version: "1.11.0" + version: "2.1.2" pool: dependency: transitive description: @@ -311,21 +332,21 @@ packages: name: pub_semver url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: name: pubspec_parse url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.2.0" shelf: dependency: transitive description: name: shelf url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.0" + version: "1.3.0" shelf_web_socket: dependency: transitive description: @@ -344,14 +365,21 @@ packages: name: source_gen url: "https://pub.flutter-io.cn" source: hosted - version: "0.9.10+4" + version: "1.2.2" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.2" source_span: dependency: transitive description: name: source_span url: "https://pub.flutter-io.cn" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -393,7 +421,7 @@ packages: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.4.3" + version: "0.4.9" timing: dependency: transitive description: @@ -407,35 +435,35 @@ packages: name: typed_data url: "https://pub.flutter-io.cn" source: hosted - version: "1.3.0" + version: "1.3.1" vector_math: dependency: transitive description: name: vector_math url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.1" + version: "2.1.2" watcher: dependency: transitive description: name: watcher url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.0" + version: "1.0.1" web_socket_channel: dependency: transitive description: name: web_socket_channel url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.0" + version: "2.2.0" yaml: dependency: transitive description: name: yaml url: "https://pub.flutter-io.cn" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.20.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=2.5.0" diff --git a/pubspec.yaml b/pubspec.yaml index 345ed8b..8ebf6bb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,24 +1,24 @@ name: tencent_kit description: A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs. -version: 3.1.0 +version: 4.0.0 # author: v7lin -homepage: https://github.com/v7lin/fake_tencent +homepage: https://github.com/RxReader/tencent_kit.git environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.20.0" + sdk: ">=2.17.0 <3.0.0" + flutter: ">=2.5.0" dependencies: flutter: sdk: flutter + plugin_platform_interface: ^2.0.2 - json_annotation: ^4.0.0 + json_annotation: ^4.5.0 dev_dependencies: flutter_test: sdk: flutter - - pedantic: + flutter_lints: ^2.0.0 build_runner: json_serializable: @@ -26,11 +26,17 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec -# The following section is specific to Flutter. +# The following section is specific to Flutter packages. flutter: # This section identifies this Flutter project as a plugin project. - # The 'pluginClass' and Android 'package' identifiers should not ordinarily - # be modified. They are used by the tooling to maintain consistency when + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when # adding or updating assets for this project. plugin: platforms: @@ -49,7 +55,7 @@ flutter: # https://flutter.dev/assets-and-images/#from-packages # # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. + # https://flutter.dev/assets-and-images/#resolution-aware # To add custom fonts to your plugin package, add a fonts section here, # in this "flutter" section. Each entry in this list should have a diff --git a/test/tencent_kit_method_channel_test.dart b/test/tencent_kit_method_channel_test.dart new file mode 100644 index 0000000..c3f1a69 --- /dev/null +++ b/test/tencent_kit_method_channel_test.dart @@ -0,0 +1,27 @@ +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tencent_kit/src/tencent_kit_method_channel.dart'; + +void main() { + final MethodChannelTencentKit platform = MethodChannelTencentKit(); + const MethodChannel channel = MethodChannel('v7lin.github.io/tencent_kit'); + + TestWidgetsFlutterBinding.ensureInitialized(); + + setUp(() { + channel.setMockMethodCallHandler((MethodCall methodCall) async { + switch(methodCall.method) { + case 'isQQInstalled': + return true; + } + }); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); + + test('getPlatformVersion', () async { + expect(await platform.isQQInstalled(), true); + }); +} diff --git a/test/tencent_kit_test.dart b/test/tencent_kit_test.dart deleted file mode 100644 index b8698ba..0000000 --- a/test/tencent_kit_test.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:pedantic/pedantic.dart'; -import 'package:tencent_kit/tencent_kit.dart'; - -void main() { - TestWidgetsFlutterBinding.ensureInitialized(); - - const MethodChannel channel = MethodChannel('v7lin.github.io/tencent_kit'); - - setUp(() { - channel.setMockMethodCallHandler((MethodCall call) async { - switch (call.method) { - case 'registerApp': - return null; - case 'isQQInstalled': - return true; - case 'isTIMInstalled': - return true; - case 'login': - unawaited(channel.binaryMessenger.handlePlatformMessage( - channel.name, - channel.codec.encodeMethodCall( - MethodCall('onLoginResp', json.decode('{"ret":-2}'))), - (ByteData? data) { - // mock success - }, - )); - return null; - case 'logout': - return null; - case 'shareMood': - case 'shareText': - case 'shareImage': - case 'shareMusic': - case 'shareWebpage': - unawaited(channel.binaryMessenger.handlePlatformMessage( - channel.name, - channel.codec.encodeMethodCall( - MethodCall('onShareResp', json.decode('{"ret":0}'))), - (ByteData? data) { - // mock success - }, - )); - return null; - } - throw PlatformException(code: '0', message: '想啥呢,升级插件不想升级Mock?'); - }); - }); - - tearDown(() { - channel.setMockMethodCallHandler(null); - }); - - test('isQQInstalled', () async { - expect(await Tencent.instance.isQQInstalled(), true); - }); - - test('isTIMInstalled', () async { - expect(await Tencent.instance.isTIMInstalled(), true); - }); - - test('login', () async { - final StreamSubscription subs = - Tencent.instance.respStream().listen((BaseResp resp) { - expect(resp.runtimeType, LoginResp); - expect(resp.ret, BaseResp.RET_USERCANCEL); - }); - await Tencent.instance.login( - scope: [ - TencentScope.GET_SIMPLE_USERINFO, - ], - ); - await Future.delayed(const Duration(seconds: 1)); - await subs.cancel(); - }); - - test('share', () async { - final StreamSubscription subs = - Tencent.instance.respStream().listen((BaseResp resp) { - expect(resp.runtimeType, ShareMsgResp); - expect(resp.ret, BaseResp.RET_SUCCESS); - }); - await Tencent.instance.shareMood( - scene: TencentScene.SCENE_QZONE, - summary: 'share text', - ); - await Future.delayed(const Duration(seconds: 1)); - await subs.cancel(); - }); -} diff --git a/test/tencent_test.dart b/test/tencent_test.dart new file mode 100644 index 0000000..0728153 --- /dev/null +++ b/test/tencent_test.dart @@ -0,0 +1,123 @@ +import 'dart:async'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:tencent_kit/src/tencent_constant.dart'; +import 'package:tencent_kit/src/tencent_kit_method_channel.dart'; +import 'package:tencent_kit/src/tencent_kit_platform_interface.dart'; +import 'package:tencent_kit/tencent_kit.dart'; + +class MockTencentKitPlatform with MockPlatformInterfaceMixin implements TencentKitPlatform { + @override + Future setIsPermissionGranted({ + required bool granted, + String? buildModel, + }) { + throw UnimplementedError(); + } + + @override + Future registerApp({ + required String appId, + String? universalLink, + }) async { + throw UnimplementedError(); + } + + @override + Future isQQInstalled() { + return Future.value(true); + } + + @override + Future isTIMInstalled() { + throw UnimplementedError(); + } + + @override + Stream respStream() { + throw UnimplementedError(); + } + + @override + Future login({ + required List scope, + }) { + throw UnimplementedError(); + } + + @override + Future logout() { + throw UnimplementedError(); + } + + @override + Future shareImage({ + required int scene, + required Uri imageUri, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError(); + } + + @override + Future shareMood({ + required int scene, + String? summary, + List? imageUris, + Uri? videoUri, + }) { + throw UnimplementedError(); + } + + @override + Future shareMusic({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String musicUrl, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError(); + } + + @override + Future shareText({ + required int scene, + required String summary, + }) { + throw UnimplementedError(); + } + + @override + Future shareWebpage({ + required int scene, + required String title, + String? summary, + Uri? imageUri, + required String targetUrl, + String? appName, + int extInt = TencentQZoneFlag.DEFAULT, + }) { + throw UnimplementedError(); + } +} + +void main() { + final TencentKitPlatform initialPlatform = TencentKitPlatform.instance; + + test('$MethodChannelTencentKit is the default instance', () { + expect(initialPlatform, isInstanceOf()); + }); + + test('getPlatformVersion', () async { + final MockTencentKitPlatform fakePlatform = MockTencentKitPlatform(); + TencentKitPlatform.instance = fakePlatform; + + expect(await Tencent.isQQInstalled(), true); + }); +}