nullsafety

This commit is contained in:
v7lin
2021-03-19 13:59:35 +08:00
parent 8489b41e34
commit 684a2ed623
33 changed files with 961 additions and 1097 deletions

View File

@ -16,19 +16,9 @@ steps:
# - name: pub-cache # - name: pub-cache
# path: /opt/flutter/.pub-cache # path: /opt/flutter/.pub-cache
# commands: # commands:
# - flutter pub run build_runner clean
# - flutter pub run build_runner build --delete-conflicting-outputs # - flutter pub run build_runner build --delete-conflicting-outputs
#- name: android-check
# image: v7lin/flutter:1.17.3-stable
# volumes:
# - name: pub-cache
# path: /opt/flutter/.pub-cache
# - name: gradle
# path: /root/.gradle
# commands:
# - cd example/android/
# - ./gradlew :wechat_kit:check
# docker run --rm -it -v ${PWD}:/src v7lin/clang:5.0.2-r0 sh -c "clang-format -style=file -i src/Classes/*.h src/Classes/*.m" # docker run --rm -it -v ${PWD}:/src v7lin/clang:5.0.2-r0 sh -c "clang-format -style=file -i src/Classes/*.h src/Classes/*.m"
#- name: ios-format #- name: ios-format
# image: v7lin/clang # image: v7lin/clang

4
.gitignore vendored
View File

@ -6,6 +6,6 @@
build/ build/
# custom #
.idea/
*.iml *.iml
.idea/

View File

@ -1,3 +1,9 @@
## 2.1.0
* nullsafety
* Android embedding v1
* Tencent
## 2.0.1 ## 2.0.1
* *

View File

@ -159,6 +159,9 @@ Capabilities -> Associated Domain -> Domain -> applinks:${your applinks}
|QQ||||||| |QQ|||||||
|QZone||||||| |QZone|||||||
* break change
* 2.1.0: nullsafety & Android embedding v1 & Tencent
* snapshot * snapshot
``` ```

View File

@ -37,7 +37,7 @@ analyzer:
# Please see https://github.com/flutter/flutter/pull/24528 for details. # Please see https://github.com/flutter/flutter/pull/24528 for details.
sdk_version_async_exported_from_core: ignore sdk_version_async_exported_from_core: ignore
exclude: exclude:
- "**/*.g.dart" - "lib/*.g.dart"
linter: linter:
rules: rules:
@ -49,6 +49,7 @@ 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_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_require_non_null_named_parameters
- always_specify_types - always_specify_types
- always_use_package_imports # we do this commonly
- annotate_overrides - annotate_overrides
# - avoid_annotating_with_dynamic # conflicts with always_specify_types # - avoid_annotating_with_dynamic # conflicts with always_specify_types
# - avoid_as # required for implicit-casts: true # - avoid_as # required for implicit-casts: true
@ -59,6 +60,7 @@ linter:
# - avoid_double_and_int_checks # only useful when targeting JS runtime # - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else - avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes - avoid_equals_and_hash_code_on_mutable_classes
# - avoid_escaping_inner_quotes # not yet tested
- avoid_field_initializers_in_const_classes - avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls - avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types # not yet tested # - avoid_implementing_value_types # not yet tested
@ -77,9 +79,10 @@ linter:
- avoid_returning_null_for_void - avoid_returning_null_for_void
# - avoid_returning_this # there are plenty of valid reasons to return this # - avoid_returning_this # there are plenty of valid reasons to return this
# - avoid_setters_without_getters # not yet tested # - avoid_setters_without_getters # not yet tested
# - avoid_shadowing_type_parameters # not yet tested - avoid_shadowing_type_parameters
- avoid_single_cascade_in_expression_statements - avoid_single_cascade_in_expression_statements
- avoid_slow_async_io - avoid_slow_async_io
# - avoid_type_to_string # we do this commonly
- avoid_types_as_parameter_names - avoid_types_as_parameter_names
# - avoid_types_on_closure_parameters # conflicts with always_specify_types # - avoid_types_on_closure_parameters # conflicts with always_specify_types
# - avoid_unnecessary_containers # not yet tested # - avoid_unnecessary_containers # not yet tested
@ -91,65 +94,71 @@ linter:
- camel_case_types - camel_case_types
- cancel_subscriptions - cancel_subscriptions
# - cascade_invocations # not yet tested # - cascade_invocations # not yet tested
- cast_nullable_to_non_nullable
# - close_sinks # not reliable enough # - close_sinks # not reliable enough
# - comment_references # blocked on https://github.com/flutter/flutter/issues/20765 # - comment_references # blocked on https://github.com/flutter/flutter/issues/20765
# - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204
- control_flow_in_finally - control_flow_in_finally
# - curly_braces_in_flow_control_structures # not yet tested # - curly_braces_in_flow_control_structures # not required by flutter style
# - diagnostic_describe_all_properties # not yet tested # - diagnostic_describe_all_properties # not yet tested
- directives_ordering - directives_ordering
# - do_not_use_environment # we do this commonly
- empty_catches - empty_catches
- empty_constructor_bodies - empty_constructor_bodies
- empty_statements - empty_statements
- file_names - exhaustive_cases
- file_names # not yet tested
- flutter_style_todos - flutter_style_todos
- hash_and_equals - hash_and_equals
- implementation_imports - implementation_imports
# - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811
- iterable_contains_unrelated_type - iterable_contains_unrelated_type
# - join_return_with_assignment # not yet tested # - join_return_with_assignment # not required by flutter style
- leading_newlines_in_multiline_strings
- library_names - library_names
- library_prefixes - library_prefixes
# - lines_longer_than_80_chars # not yet tested # - lines_longer_than_80_chars # not required by flutter style
- list_remove_unrelated_type - list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
# - missing_whitespace_between_adjacent_strings # not yet tested # - missing_whitespace_between_adjacent_strings # not yet tested
- no_adjacent_strings_in_list - no_adjacent_strings_in_list
# - no_default_cases # too many false positives
- no_duplicate_case_values - no_duplicate_case_values
# - no_logic_in_create_state # not yet tested - no_logic_in_create_state
# - no_runtimeType_toString # not yet tested # - no_runtimeType_toString # ok in tests; we enable this only in packages/
- non_constant_identifier_names - non_constant_identifier_names
# - null_closures # not yet tested - null_check_on_nullable_type_parameter
# - null_closures # not required by flutter style
# - omit_local_variable_types # opposite of always_specify_types # - omit_local_variable_types # opposite of always_specify_types
# - one_member_abstracts # too many false positives # - one_member_abstracts # too many false positives
# - only_throw_errors # https://github.com/flutter/flutter/issues/5792 # - only_throw_errors # https://github.com/flutter/flutter/issues/5792
- overridden_fields - overridden_fields
- package_api_docs - package_api_docs
- package_names # - package_names # non conforming packages in sdk
- package_prefixed_library_names - package_prefixed_library_names
# - parameter_assignments # we do this commonly # - parameter_assignments # we do this commonly
- prefer_adjacent_string_concatenation - prefer_adjacent_string_concatenation
- prefer_asserts_in_initializer_lists - prefer_asserts_in_initializer_lists
# - prefer_asserts_with_message # not yet tested # - prefer_asserts_with_message # not required by flutter style
- prefer_collection_literals - prefer_collection_literals
- prefer_conditional_assignment - prefer_conditional_assignment
- prefer_const_constructors - prefer_const_constructors
- prefer_const_constructors_in_immutables - prefer_const_constructors_in_immutables
- prefer_const_declarations - prefer_const_declarations
- prefer_const_literals_to_create_immutables - prefer_const_literals_to_create_immutables
# - prefer_constructors_over_static_methods # not yet tested # - prefer_constructors_over_static_methods # far too many false positives
- prefer_contains - prefer_contains
# - prefer_double_quotes # opposite of prefer_single_quotes # - prefer_double_quotes # opposite of prefer_single_quotes
- prefer_equal_for_default_values - prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields - prefer_final_fields
# - prefer_final_in_for_each - prefer_final_in_for_each
# - prefer_final_locals - prefer_final_locals
- prefer_for_elements_to_map_fromIterable - prefer_for_elements_to_map_fromIterable
# - prefer_foreach - prefer_foreach
# - prefer_function_declarations_over_variables # not yet tested # - prefer_function_declarations_over_variables # not yet tested
- prefer_generic_function_type_aliases - prefer_generic_function_type_aliases
# - prefer_if_elements_to_conditional_expressions - prefer_if_elements_to_conditional_expressions
- prefer_if_null_operators - prefer_if_null_operators
- prefer_initializing_formals - prefer_initializing_formals
- prefer_inlined_adds - prefer_inlined_adds
@ -169,13 +178,15 @@ linter:
# - provide_deprecation_message # not yet tested # - provide_deprecation_message # not yet tested
# - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml
- recursive_getters - recursive_getters
# - sized_box_for_whitespace # not yet tested
- slash_for_doc_comments - slash_for_doc_comments
# - sort_child_properties_last # not yet tested # - sort_child_properties_last # not yet tested
- sort_constructors_first - sort_constructors_first
- sort_pub_dependencies # - sort_pub_dependencies # prevents separating pinned transitive dependencies
- sort_unnamed_constructors_first - sort_unnamed_constructors_first
- test_types_in_equals - test_types_in_equals
- throw_in_finally - throw_in_finally
- tighten_type_of_initializing_formals
# - type_annotate_public_apis # subset of always_specify_types # - type_annotate_public_apis # subset of always_specify_types
- type_init_formals - type_init_formals
- unawaited_futures # too many false positives - unawaited_futures # too many false positives
@ -187,18 +198,24 @@ linter:
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- unnecessary_new - unnecessary_new
- unnecessary_null_aware_assignments - unnecessary_null_aware_assignments
# - unnecessary_null_checks # not yet tested
- unnecessary_null_in_if_null_operators - unnecessary_null_in_if_null_operators
- unnecessary_nullable_for_final_variable_declarations
- unnecessary_overrides - unnecessary_overrides
- unnecessary_parenthesis - unnecessary_parenthesis
# - unnecessary_raw_strings # not yet tested
- unnecessary_statements - unnecessary_statements
- unnecessary_string_escapes
- unnecessary_string_interpolations - unnecessary_string_interpolations
- unnecessary_this - unnecessary_this
- unrelated_type_equality_checks - unrelated_type_equality_checks
# - unsafe_html # not yet tested # - unsafe_html # not yet tested
- use_full_hex_values_for_flutter_colors - use_full_hex_values_for_flutter_colors
# - use_function_type_syntax_for_parameters # not yet tested # - use_function_type_syntax_for_parameters # not yet tested
- use_is_even_rather_than_modulo
# - use_key_in_widget_constructors # not yet tested # - use_key_in_widget_constructors # not yet tested
- use_late_for_private_fields_and_variables - use_late_for_private_fields_and_variables
- use_raw_strings
- use_rethrow_when_possible - use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested # - use_setters_to_change_properties # not yet tested
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182

View File

@ -1,5 +1,5 @@
group 'io.github.v7lin.tencent_kit' group 'io.github.v7lin.tencent_kit'
version '2.0.1' version '2.1.0'
buildscript { buildscript {
repositories { repositories {
@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.4' classpath 'com.android.tools.build:gradle:4.1.0'
} }
} }

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@ -1,514 +0,0 @@
package io.github.v7lin.tencent_kit;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.tencent.connect.common.Constants;
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzonePublish;
import com.tencent.connect.share.QzoneShare;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.github.v7lin.tencent_kit.content.TencentKitFileProvider;
public class TencentKit implements MethodChannel.MethodCallHandler, PluginRegistry.ActivityResultListener {
private static class TencentScene {
static final int SCENE_QQ = 0;
static final int SCENE_QZONE = 1;
}
private static class TencentRetCode {
// 网络请求成功发送至服务器,并且服务器返回数据格式正确
// 这里包括所请求业务操作失败的情况,例如没有授权等原因导致
static final int RET_SUCCESS = 0;
// 网络异常,或服务器返回的数据格式不正确导致无法解析
static final int RET_FAILED = 1;
static final int RET_COMMON = -1;
static final int RET_USERCANCEL = -2;
}
//
private static final String METHOD_REGISTERAPP = "registerApp";
private static final String METHOD_ISQQINSTALLED = "isQQInstalled";
private static final String METHOD_ISTIMINSTALLED = "isTIMInstalled";
private static final String METHOD_LOGIN = "login";
private static final String METHOD_LOGOUT = "logout";
private static final String METHOD_SHAREMOOD = "shareMood";
private static final String METHOD_SHARETEXT = "shareText";
private static final String METHOD_SHAREIMAGE = "shareImage";
private static final String METHOD_SHAREMUSIC = "shareMusic";
private static final String METHOD_SHAREWEBPAGE = "shareWebpage";
private static final String METHOD_ONLOGINRESP = "onLoginResp";
private static final String METHOD_ONSHARERESP = "onShareResp";
private static final String ARGUMENT_KEY_APPID = "appId";
// private static final String ARGUMENT_KEY_UNIVERSALLINK = "universalLink";
private static final String ARGUMENT_KEY_SCOPE = "scope";
private static final String ARGUMENT_KEY_SCENE = "scene";
private static final String ARGUMENT_KEY_TITLE = "title";
private static final String ARGUMENT_KEY_SUMMARY = "summary";
private static final String ARGUMENT_KEY_IMAGEURI = "imageUri";
private static final String ARGUMENT_KEY_IMAGEURIS = "imageUris";
private static final String ARGUMENT_KEY_VIDEOURI = "videoUri";
private static final String ARGUMENT_KEY_MUSICURL = "musicUrl";
private static final String ARGUMENT_KEY_TARGETURL = "targetUrl";
private static final String ARGUMENT_KEY_APPNAME = "appName";
private static final String ARGUMENT_KEY_EXTINT = "extInt";
private static final String ARGUMENT_KEY_RESULT_RET = "ret";
private static final String ARGUMENT_KEY_RESULT_MSG = "msg";
private static final String ARGUMENT_KEY_RESULT_OPENID = "openid";
private static final String ARGUMENT_KEY_RESULT_ACCESS_TOKEN = "access_token";
private static final String ARGUMENT_KEY_RESULT_EXPIRES_IN = "expires_in";
private static final String ARGUMENT_KEY_RESULT_CREATE_AT = "create_at";
private static final String SCHEME_FILE = "file";
//
private Context applicationContext;
private Activity activity;
private MethodChannel channel;
private Tencent tencent;
public TencentKit() {
super();
}
public TencentKit(Context applicationContext, Activity activity) {
this.applicationContext = applicationContext;
this.activity = activity;
}
//
public void setApplicationContext(@Nullable Context applicationContext) {
this.applicationContext = applicationContext;
}
public void setActivity(@Nullable Activity activity) {
this.activity = activity;
}
public void startListening(@NonNull BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "v7lin.github.io/tencent_kit");
channel.setMethodCallHandler(this);
}
public void stopListening() {
channel.setMethodCallHandler(null);
channel = null;
}
// --- MethodCallHandler
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (METHOD_REGISTERAPP.equals(call.method)) {
final String appId = call.argument(ARGUMENT_KEY_APPID);
// final String universalLink = call.argument(ARGUMENT_KEY_UNIVERSALLINK);
String authority = null;
try {
ProviderInfo providerInfo = applicationContext.getPackageManager().getProviderInfo(new ComponentName(applicationContext, TencentKitFileProvider.class), PackageManager.MATCH_DEFAULT_ONLY);
authority = providerInfo.authority;
} catch (PackageManager.NameNotFoundException e) {
// ignore
}
if (!TextUtils.isEmpty(authority)) {
tencent = Tencent.createInstance(appId, applicationContext, authority);
} else {
tencent = Tencent.createInstance(appId, applicationContext);
}
result.success(null);
} else if (METHOD_ISQQINSTALLED.equals(call.method)) {
result.success(isAppInstalled(applicationContext, "com.tencent.mobileqq"));
} else if (METHOD_ISTIMINSTALLED.equals(call.method)) {
result.success(isAppInstalled(applicationContext, "com.tencent.tim"));
} else if (METHOD_LOGIN.equals(call.method)) {
login(call, result);
} else if (METHOD_LOGOUT.equals(call.method)) {
logout(call, result);
} else if (METHOD_SHAREMOOD.equals(call.method)) {
shareMood(call, result);
} else if (METHOD_SHARETEXT.equals(call.method)) {
shareText(call, result);
} else if (METHOD_SHAREIMAGE.equals(call.method)) {
shareImage(call, result);
} else if (METHOD_SHAREMUSIC.equals(call.method)) {
shareMusic(call, result);
} else if (METHOD_SHAREWEBPAGE.equals(call.method)) {
shareWebpage(call, result);
} else {
result.notImplemented();
}
}
private void login(MethodCall call, MethodChannel.Result result) {
String scope = call.argument(ARGUMENT_KEY_SCOPE);
if (tencent != null) {
tencent.login(activity, scope, loginListener);
}
result.success(null);
}
private IUiListener loginListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Map<String, Object> 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;
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();
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);
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, "openId or accessToken is null.");
}
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, msg);
}
}
} catch (JSONException e) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage());
}
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onError(UiError uiError) {
// 登录失败
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, uiError.errorMessage);
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onCancel() {
// 取消登录
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL);
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onWarning(int code) {
}
};
private void logout(MethodCall call, MethodChannel.Result result) {
if (tencent != null) {
tencent.logout(applicationContext);
}
result.success(null);
}
private void shareMood(MethodCall call, MethodChannel.Result result) {
int scene = call.argument(ARGUMENT_KEY_SCENE);
if (scene == TencentScene.SCENE_QZONE) {
String summary = call.argument(ARGUMENT_KEY_SUMMARY);
List<String> imageUris = call.argument(ARGUMENT_KEY_IMAGEURIS);
String videoUri = call.argument(ARGUMENT_KEY_VIDEOURI);
Bundle params = new Bundle();
if (!TextUtils.isEmpty(summary)) {
params.putString(QzonePublish.PUBLISH_TO_QZONE_SUMMARY, summary);
}
if (imageUris != null && !imageUris.isEmpty()) {
ArrayList<String> 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();
params.putString(QzonePublish.PUBLISH_TO_QZONE_VIDEO_PATH, videoPath);
params.putInt(QzonePublish.PUBLISH_TO_QZONE_KEY_TYPE, QzonePublish.PUBLISH_TO_QZONE_TYPE_PUBLISHVIDEO);
} else {
params.putInt(QzonePublish.PUBLISH_TO_QZONE_KEY_TYPE, QzonePublish.PUBLISH_TO_QZONE_TYPE_PUBLISHMOOD);
}
if (tencent != null) {
tencent.publishToQzone(activity, params, shareListener);
}
}
result.success(null);
}
private void shareText(MethodCall call, MethodChannel.Result result) {
int scene = call.argument(ARGUMENT_KEY_SCENE);
if (scene == TencentScene.SCENE_QQ) {
String summary = call.argument(ARGUMENT_KEY_SUMMARY);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, summary);
sendIntent.setType("text/*");
// 普通大众版 > 办公简洁版 > 急速轻聊版
PackageManager packageManager = applicationContext.getPackageManager();
List<PackageInfo> 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) {
if (packageName.equals(info.packageName)) {
sendIntent.setPackage(packageName);
if (sendIntent.resolveActivity(applicationContext.getPackageManager()) != null) {
sendIntent.setComponent(new ComponentName(packageName, "com.tencent.mobileqq.activity.JumpActivity"));
activity.startActivity(sendIntent);
break;
}
}
}
}
}
}
result.success(null);
}
private void shareImage(MethodCall call, MethodChannel.Result result) {
int scene = call.argument(ARGUMENT_KEY_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);
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)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activity, params, shareListener);
}
}
result.success(null);
}
private void shareMusic(MethodCall call, MethodChannel.Result result) {
int scene = call.argument(ARGUMENT_KEY_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);
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_AUDIO);
params.putString(QQShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath());
} else {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri);
}
}
params.putString(QQShare.SHARE_TO_QQ_AUDIO_URL, musicUrl);
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (!TextUtils.isEmpty(appName)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activity, params, shareListener);
}
}
result.success(null);
}
private void shareWebpage(MethodCall call, MethodChannel.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);
Bundle params = new Bundle();
switch (scene) {
case TencentScene.SCENE_QQ:
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);
params.putString(QQShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath());
} else {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri);
}
}
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (!TextUtils.isEmpty(appName)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activity, params, shareListener);
}
break;
case TencentScene.SCENE_QZONE:
params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE, QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT);
params.putString(QzoneShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
ArrayList<String> uris = new ArrayList<>();
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
uris.add(uri.getPath());
} else {
uris.add(imageUri);
}
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, uris);
}
params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (tencent != null) {
tencent.shareToQzone(activity, params, shareListener);
}
break;
default:
break;
}
result.success(null);
}
private IUiListener shareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Map<String, Object> 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;
if (ret == TencentRetCode.RET_SUCCESS) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_SUCCESS);
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, msg);
}
}
} catch (JSONException e) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage());
}
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onError(UiError error) {
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, error.errorMessage);
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onCancel() {
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL);
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onWarning(int code) {
if (code == Constants.ERROR_NO_AUTHORITY) {
// 如果authorities为空sdk会回调这个接口提醒开发者适配FileProvider
}
}
};
// --- ActivityResultListener
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Constants.REQUEST_LOGIN:
return Tencent.onActivityResultData(requestCode, resultCode, data, loginListener);
case Constants.REQUEST_QQ_SHARE:
case Constants.REQUEST_QZONE_SHARE:
return Tencent.onActivityResultData(requestCode, resultCode, data, shareListener);
default:
break;
}
return false;
}
// ---
private static boolean isAppInstalled(Context context, String packageName) {
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
}
return packageInfo != null;
}
}

View File

@ -1,62 +1,135 @@
package io.github.v7lin.tencent_kit; package io.github.v7lin.tencent_kit;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.tencent.connect.common.Constants;
import com.tencent.connect.share.QQShare;
import com.tencent.connect.share.QzonePublish;
import com.tencent.connect.share.QzoneShare;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.ActivityResultListener;
import io.github.v7lin.tencent_kit.content.TencentKitFileProvider;
/** /**
* TencentKitPlugin * TencentKitPlugin
*/ */
public class TencentKitPlugin implements FlutterPlugin, ActivityAware { public class TencentKitPlugin implements FlutterPlugin, ActivityAware, ActivityResultListener, MethodCallHandler {
// This static function is optional and equivalent to onAttachedToEngine. It supports the old
// pre-Flutter-1.12 Android projects. You are encouraged to continue supporting private static class TencentScene {
// plugin registration via this function while apps migrate to use the new Android APIs static final int SCENE_QQ = 0;
// post-flutter-1.12 via https://flutter.dev/go/android-project-migration. static final int SCENE_QZONE = 1;
//
// It is encouraged to share logic between onAttachedToEngine and registerWith to keep
// them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
// depending on the user's project. onAttachedToEngine or registerWith must both be defined
// in the same class.
public static void registerWith(PluginRegistry.Registrar registrar) {
TencentKit tencentKit = new TencentKit(registrar.context(), registrar.activity());
registrar.addActivityResultListener(tencentKit);
tencentKit.startListening(registrar.messenger());
} }
private static class TencentRetCode {
// 网络请求成功发送至服务器,并且服务器返回数据格式正确
// 这里包括所请求业务操作失败的情况,例如没有授权等原因导致
static final int RET_SUCCESS = 0;
// 网络异常,或服务器返回的数据格式不正确导致无法解析
static final int RET_FAILED = 1;
static final int RET_COMMON = -1;
static final int RET_USERCANCEL = -2;
}
//
private static final String METHOD_REGISTERAPP = "registerApp";
private static final String METHOD_ISQQINSTALLED = "isQQInstalled";
private static final String METHOD_ISTIMINSTALLED = "isTIMInstalled";
private static final String METHOD_LOGIN = "login";
private static final String METHOD_LOGOUT = "logout";
private static final String METHOD_SHAREMOOD = "shareMood";
private static final String METHOD_SHARETEXT = "shareText";
private static final String METHOD_SHAREIMAGE = "shareImage";
private static final String METHOD_SHAREMUSIC = "shareMusic";
private static final String METHOD_SHAREWEBPAGE = "shareWebpage";
private static final String METHOD_ONLOGINRESP = "onLoginResp";
private static final String METHOD_ONSHARERESP = "onShareResp";
private static final String ARGUMENT_KEY_APPID = "appId";
// private static final String ARGUMENT_KEY_UNIVERSALLINK = "universalLink";
private static final String ARGUMENT_KEY_SCOPE = "scope";
private static final String ARGUMENT_KEY_SCENE = "scene";
private static final String ARGUMENT_KEY_TITLE = "title";
private static final String ARGUMENT_KEY_SUMMARY = "summary";
private static final String ARGUMENT_KEY_IMAGEURI = "imageUri";
private static final String ARGUMENT_KEY_IMAGEURIS = "imageUris";
private static final String ARGUMENT_KEY_VIDEOURI = "videoUri";
private static final String ARGUMENT_KEY_MUSICURL = "musicUrl";
private static final String ARGUMENT_KEY_TARGETURL = "targetUrl";
private static final String ARGUMENT_KEY_APPNAME = "appName";
private static final String ARGUMENT_KEY_EXTINT = "extInt";
private static final String ARGUMENT_KEY_RESULT_RET = "ret";
private static final String ARGUMENT_KEY_RESULT_MSG = "msg";
private static final String ARGUMENT_KEY_RESULT_OPENID = "openid";
private static final String ARGUMENT_KEY_RESULT_ACCESS_TOKEN = "access_token";
private static final String ARGUMENT_KEY_RESULT_EXPIRES_IN = "expires_in";
private static final String ARGUMENT_KEY_RESULT_CREATE_AT = "create_at";
private static final String SCHEME_FILE = "file";
/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private MethodChannel channel;
private Context applicationContext;
private ActivityPluginBinding activityPluginBinding;
private Tencent tencent;
// --- FlutterPlugin // --- FlutterPlugin
private final TencentKit tencentKit;
private ActivityPluginBinding pluginBinding;
public TencentKitPlugin() {
tencentKit = new TencentKit();
}
@Override @Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
tencentKit.setApplicationContext(binding.getApplicationContext()); channel = new MethodChannel(binding.getBinaryMessenger(), "v7lin.github.io/tencent_kit");
tencentKit.setActivity(null); channel.setMethodCallHandler(this);
tencentKit.startListening(binding.getBinaryMessenger()); applicationContext = binding.getApplicationContext();
} }
@Override @Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
tencentKit.stopListening(); channel.setMethodCallHandler(null);
tencentKit.setActivity(null); channel = null;
tencentKit.setApplicationContext(null); applicationContext = null;
} }
// --- ActivityAware // --- ActivityAware
@Override @Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
tencentKit.setActivity(binding.getActivity()); activityPluginBinding = binding;
pluginBinding = binding; activityPluginBinding.addActivityResultListener(this);
pluginBinding.addActivityResultListener(tencentKit);
} }
@Override @Override
@ -71,8 +144,389 @@ public class TencentKitPlugin implements FlutterPlugin, ActivityAware {
@Override @Override
public void onDetachedFromActivity() { public void onDetachedFromActivity() {
tencentKit.setActivity(null); activityPluginBinding.removeActivityResultListener(this);
pluginBinding.removeActivityResultListener(tencentKit); activityPluginBinding = null;
pluginBinding = null; }
// --- ActivityResultListener
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case Constants.REQUEST_LOGIN:
return Tencent.onActivityResultData(requestCode, resultCode, data, loginListener);
case Constants.REQUEST_QQ_SHARE:
case Constants.REQUEST_QZONE_SHARE:
return Tencent.onActivityResultData(requestCode, resultCode, data, shareListener);
default:
break;
}
return false;
}
// --- MethodCallHandler
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (METHOD_REGISTERAPP.equals(call.method)) {
final String appId = call.argument(ARGUMENT_KEY_APPID);
// final String universalLink = call.argument(ARGUMENT_KEY_UNIVERSALLINK);
String authority = null;
try {
ProviderInfo providerInfo = applicationContext.getPackageManager().getProviderInfo(new ComponentName(applicationContext, TencentKitFileProvider.class), PackageManager.MATCH_DEFAULT_ONLY);
authority = providerInfo.authority;
} catch (PackageManager.NameNotFoundException e) {
// ignore
}
if (!TextUtils.isEmpty(authority)) {
tencent = Tencent.createInstance(appId, applicationContext, authority);
} else {
tencent = Tencent.createInstance(appId, applicationContext);
}
result.success(null);
} else if (METHOD_ISQQINSTALLED.equals(call.method)) {
result.success(isAppInstalled(applicationContext, "com.tencent.mobileqq"));
} else if (METHOD_ISTIMINSTALLED.equals(call.method)) {
result.success(isAppInstalled(applicationContext, "com.tencent.tim"));
} else if (METHOD_LOGIN.equals(call.method)) {
login(call, result);
} else if (METHOD_LOGOUT.equals(call.method)) {
logout(call, result);
} else if (METHOD_SHAREMOOD.equals(call.method)) {
shareMood(call, result);
} else if (METHOD_SHARETEXT.equals(call.method)) {
shareText(call, result);
} else if (METHOD_SHAREIMAGE.equals(call.method)) {
shareImage(call, result);
} else if (METHOD_SHAREMUSIC.equals(call.method)) {
shareMusic(call, result);
} else if (METHOD_SHAREWEBPAGE.equals(call.method)) {
shareWebpage(call, result);
} else {
result.notImplemented();
}
}
private void login(@NonNull MethodCall call, @NonNull Result result) {
String scope = call.argument(ARGUMENT_KEY_SCOPE);
if (tencent != null) {
tencent.login(activityPluginBinding.getActivity(), scope, loginListener);
}
result.success(null);
}
private IUiListener loginListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Map<String, Object> 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;
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();
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);
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, "openId or accessToken is null.");
}
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, msg);
}
}
} catch (JSONException e) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage());
}
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onError(UiError uiError) {
// 登录失败
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, uiError.errorMessage);
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onCancel() {
// 取消登录
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL);
if (channel != null) {
channel.invokeMethod(METHOD_ONLOGINRESP, map);
}
}
@Override
public void onWarning(int code) {
}
};
private void logout(@NonNull MethodCall call, @NonNull Result result) {
if (tencent != null) {
tencent.logout(applicationContext);
}
result.success(null);
}
private void shareMood(@NonNull MethodCall call, @NonNull Result result) {
int scene = call.argument(ARGUMENT_KEY_SCENE);
if (scene == TencentScene.SCENE_QZONE) {
String summary = call.argument(ARGUMENT_KEY_SUMMARY);
List<String> imageUris = call.argument(ARGUMENT_KEY_IMAGEURIS);
String videoUri = call.argument(ARGUMENT_KEY_VIDEOURI);
Bundle params = new Bundle();
if (!TextUtils.isEmpty(summary)) {
params.putString(QzonePublish.PUBLISH_TO_QZONE_SUMMARY, summary);
}
if (imageUris != null && !imageUris.isEmpty()) {
ArrayList<String> 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();
params.putString(QzonePublish.PUBLISH_TO_QZONE_VIDEO_PATH, videoPath);
params.putInt(QzonePublish.PUBLISH_TO_QZONE_KEY_TYPE, QzonePublish.PUBLISH_TO_QZONE_TYPE_PUBLISHVIDEO);
} else {
params.putInt(QzonePublish.PUBLISH_TO_QZONE_KEY_TYPE, QzonePublish.PUBLISH_TO_QZONE_TYPE_PUBLISHMOOD);
}
if (tencent != null) {
tencent.publishToQzone(activityPluginBinding.getActivity(), params, shareListener);
}
}
result.success(null);
}
private void shareText(@NonNull MethodCall call, @NonNull Result result) {
int scene = call.argument(ARGUMENT_KEY_SCENE);
if (scene == TencentScene.SCENE_QQ) {
String summary = call.argument(ARGUMENT_KEY_SUMMARY);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, summary);
sendIntent.setType("text/*");
// 普通大众版 > 办公简洁版 > 急速轻聊版
PackageManager packageManager = applicationContext.getPackageManager();
List<PackageInfo> 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) {
if (packageName.equals(info.packageName)) {
sendIntent.setPackage(packageName);
if (sendIntent.resolveActivity(applicationContext.getPackageManager()) != null) {
sendIntent.setComponent(new ComponentName(packageName, "com.tencent.mobileqq.activity.JumpActivity"));
activityPluginBinding.getActivity().startActivity(sendIntent);
break;
}
}
}
}
}
}
result.success(null);
}
private void shareImage(@NonNull MethodCall call, @NonNull Result result) {
int scene = call.argument(ARGUMENT_KEY_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);
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)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activityPluginBinding.getActivity(), params, shareListener);
}
}
result.success(null);
}
private void shareMusic(@NonNull MethodCall call, @NonNull Result result) {
int scene = call.argument(ARGUMENT_KEY_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);
Bundle params = new Bundle();
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_AUDIO);
params.putString(QQShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath());
} else {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri);
}
}
params.putString(QQShare.SHARE_TO_QQ_AUDIO_URL, musicUrl);
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (!TextUtils.isEmpty(appName)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activityPluginBinding.getActivity(), params, shareListener);
}
}
result.success(null);
}
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);
Bundle params = new Bundle();
switch (scene) {
case TencentScene.SCENE_QQ:
params.putInt(QQShare.SHARE_TO_QQ_KEY_TYPE, QQShare.SHARE_TO_QQ_TYPE_DEFAULT);
params.putString(QQShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QQShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, uri.getPath());
} else {
params.putString(QQShare.SHARE_TO_QQ_IMAGE_URL, imageUri);
}
}
params.putString(QQShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (!TextUtils.isEmpty(appName)) {
params.putString(QQShare.SHARE_TO_QQ_APP_NAME, appName);
}
params.putInt(QQShare.SHARE_TO_QQ_EXT_INT, extInt);
if (tencent != null) {
tencent.shareToQQ(activityPluginBinding.getActivity(), params, shareListener);
}
break;
case TencentScene.SCENE_QZONE:
params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE, QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT);
params.putString(QzoneShare.SHARE_TO_QQ_TITLE, title);
if (!TextUtils.isEmpty(summary)) {
params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, summary);
}
if (!TextUtils.isEmpty(imageUri)) {
ArrayList<String> uris = new ArrayList<>();
Uri uri = Uri.parse(imageUri);
if (TextUtils.equals(SCHEME_FILE, uri.getScheme())) {
uris.add(uri.getPath());
} else {
uris.add(imageUri);
}
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL, uris);
}
params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL, targetUrl);
if (tencent != null) {
tencent.shareToQzone(activityPluginBinding.getActivity(), params, shareListener);
}
break;
default:
break;
}
result.success(null);
}
private IUiListener shareListener = new IUiListener() {
@Override
public void onComplete(Object o) {
Map<String, Object> 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;
if (ret == TencentRetCode.RET_SUCCESS) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_SUCCESS);
} else {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, msg);
}
}
} catch (JSONException e) {
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, e.getMessage());
}
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onError(UiError error) {
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_COMMON);
map.put(ARGUMENT_KEY_RESULT_MSG, error.errorMessage);
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onCancel() {
Map<String, Object> map = new HashMap<>();
map.put(ARGUMENT_KEY_RESULT_RET, TencentRetCode.RET_USERCANCEL);
if (channel != null) {
channel.invokeMethod(METHOD_ONSHARERESP, map);
}
}
@Override
public void onWarning(int code) {
if (code == Constants.ERROR_NO_AUTHORITY) {
// 如果authorities为空sdk会回调这个接口提醒开发者适配FileProvider
}
}
};
// ---
private static boolean isAppInstalled(Context context, String packageName) {
PackageInfo packageInfo = null;
try {
packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
}
return packageInfo != null;
} }
} }

7
example/.gitignore vendored
View File

@ -22,6 +22,7 @@
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/ .dart_tool/
.flutter-plugins .flutter-plugins
.flutter-plugins-dependencies .flutter-plugins-dependencies
@ -39,5 +40,7 @@ app.*.symbols
# Obfuscation related # Obfuscation related
app.*.map.json app.*.map.json
# Exceptions to above rules. # Android Studio will place build artifacts here
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages /android/app/debug
/android/app/profile
/android/app/release

View File

@ -5,3 +5,7 @@ gradle-wrapper.jar
/gradlew.bat /gradlew.bat
/local.properties /local.properties
GeneratedPluginRegistrant.java GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties

View File

@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.4' classpath 'com.android.tools.build:gradle:4.1.0'
} }
} }

View File

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip

View File

@ -2,12 +2,16 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:okhttp_kit/okhttp_kit.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:tencent_kit/tencent_kit.dart'; import 'package:tencent_kit/tencent_kit.dart';
void main() => runApp(MyApp()); const String _TENCENT_APPID = 'your tencent appId';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Tencent.instance.registerApp(appId: _TENCENT_APPID);
runApp(MyApp());
}
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@override @override
@ -26,39 +30,33 @@ class Home extends StatefulWidget {
} }
class _HomeState extends State<Home> { class _HomeState extends State<Home> {
static const String _TENCENT_APPID = 'your tencent appId'; late final StreamSubscription<TencentLoginResp> _login =
Tencent.instance.loginResp().listen(_listenLogin);
late final StreamSubscription<TencentSdkResp> _share =
Tencent.instance.shareResp().listen(_listenShare);
final Tencent _tencent = Tencent()..registerApp(appId: _TENCENT_APPID); TencentLoginResp? _loginResp;
StreamSubscription<TencentLoginResp> _login;
StreamSubscription<TencentShareResp> _share;
TencentLoginResp _loginResp;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_login = _tencent.loginResp().listen(_listenLogin);
_share = _tencent.shareResp().listen(_listenShare);
} }
void _listenLogin(TencentLoginResp resp) { void _listenLogin(TencentLoginResp resp) {
_loginResp = resp; _loginResp = resp;
String content = 'login: ${resp.openid} - ${resp.accessToken}'; final String content = 'login: ${resp.openid} - ${resp.accessToken}';
_showTips('登录', content); _showTips('登录', content);
} }
void _listenShare(TencentShareResp resp) { void _listenShare(TencentSdkResp resp) {
String content = 'share: ${resp.ret} - ${resp.msg}'; final String content = 'share: ${resp.ret} - ${resp.msg}';
_showTips('分享', content); _showTips('分享', content);
} }
@override @override
void dispose() { void dispose() {
_login?.cancel(); _login.cancel();
_login = null; _share.cancel();
_share?.cancel();
_share = null;
super.dispose(); super.dispose();
} }
@ -73,15 +71,15 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('环境检查'), title: const Text('环境检查'),
onTap: () async { onTap: () async {
String content = final String content =
'QQ install: ${await _tencent.isQQInstalled()}\nTIM install: ${await _tencent.isTIMInstalled()}'; 'QQ install: ${await Tencent.instance.isQQInstalled()}\nTIM install: ${await Tencent.instance.isTIMInstalled()}';
_showTips('环境检查', content); _showTips('环境检查', content);
}, },
), ),
ListTile( ListTile(
title: const Text('登录'), title: const Text('登录'),
onTap: () { onTap: () {
_tencent.login( Tencent.instance.login(
scope: <String>[TencentScope.GET_SIMPLE_USERINFO], scope: <String>[TencentScope.GET_SIMPLE_USERINFO],
); );
}, },
@ -89,13 +87,13 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('获取用户信息'), title: const Text('获取用户信息'),
onTap: () async { onTap: () async {
if (_loginResp != null && if ((_loginResp?.isSuccessful ?? false) &&
_loginResp.isSuccessful && !(_loginResp!.isExpired ?? true)) {
!_loginResp.isExpired) { final TencentUserInfoResp userInfo =
TencentUserInfoResp userInfo = await _tencent.getUserInfo( await Tencent.instance.getUserInfo(
appId: _TENCENT_APPID, appId: _TENCENT_APPID,
openid: _loginResp.openid, openid: _loginResp!.openid!,
accessToken: _loginResp.accessToken, accessToken: _loginResp!.accessToken!,
); );
if (userInfo.isSuccessful) { if (userInfo.isSuccessful) {
_showTips('用户信息', _showTips('用户信息',
@ -109,11 +107,11 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('获取UnionID'), title: const Text('获取UnionID'),
onTap: () async { onTap: () async {
if (_loginResp != null && if ((_loginResp?.isSuccessful ?? false) &&
_loginResp.isSuccessful && !(_loginResp!.isExpired ?? true)) {
!_loginResp.isExpired) { final TencentUnionidResp unionid =
TencentUnionidResp unionid = await _tencent.getUnionId( await Tencent.instance.getUnionId(
accessToken: _loginResp.accessToken, accessToken: _loginResp!.accessToken!,
); );
if (unionid.isSuccessful) { if (unionid.isSuccessful) {
_showTips('UnionID', _showTips('UnionID',
@ -128,7 +126,7 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('分享说说'), title: const Text('分享说说'),
onTap: () { onTap: () {
_tencent.shareMood( Tencent.instance.shareMood(
scene: TencentScene.SCENE_QZONE, scene: TencentScene.SCENE_QZONE,
summary: '分享测试', summary: '分享测试',
); );
@ -137,7 +135,7 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('文本分享'), title: const Text('文本分享'),
onTap: () { onTap: () {
_tencent.shareText( Tencent.instance.shareText(
scene: TencentScene.SCENE_QQ, scene: TencentScene.SCENE_QQ,
summary: '分享测试', summary: '分享测试',
); );
@ -146,37 +144,18 @@ class _HomeState extends State<Home> {
ListTile( ListTile(
title: const Text('图片分享'), title: const Text('图片分享'),
onTap: () async { onTap: () async {
OkHttpClient client = OkHttpClientBuilder().build(); final File file = await DefaultCacheManager().getSingleFile(
Response resp = await client 'https://www.baidu.com/img/bd_logo1.png?where=super');
.newCall(RequestBuilder() await Tencent.instance.shareImage(
.get()
.url(HttpUrl.parse(
'https://www.baidu.com/img/bd_logo1.png?where=super'))
.build())
.enqueue();
if (resp.isSuccessful()) {
Directory saveDir = Platform.isIOS
? await path_provider.getApplicationDocumentsDirectory()
: await path_provider.getExternalStorageDirectory();
File saveFile = File(path.join(saveDir.path, 'timg.png'));
if (!saveFile.existsSync()) {
saveFile.createSync(recursive: true);
saveFile.writeAsBytesSync(
await resp.body().bytes(),
flush: true,
);
}
await _tencent.shareImage(
scene: TencentScene.SCENE_QQ, scene: TencentScene.SCENE_QQ,
imageUri: Uri.file(saveFile.path), imageUri: Uri.file(file.path),
); );
}
}, },
), ),
ListTile( ListTile(
title: const Text('网页分享'), title: const Text('网页分享'),
onTap: () { onTap: () {
_tencent.shareWebpage( Tencent.instance.shareWebpage(
scene: TencentScene.SCENE_QQ, scene: TencentScene.SCENE_QQ,
title: 'title', title: 'title',
targetUrl: 'https://www.baidu.com/', targetUrl: 'https://www.baidu.com/',

View File

@ -1,212 +1,233 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.2"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.0-nullsafety.1" version: "2.5.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.1" version: "2.1.0"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.3" version: "1.1.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
name: charcode name: charcode
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.1" version: "1.1.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.15.0-nullsafety.3" version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.5" version: "3.0.0"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
name: cupertino_icons name: cupertino_icons
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.3" version: "1.0.2"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.3" version: "1.0.0"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.2.1" version: "6.1.0"
fixnum:
dependency: transitive
description:
name: fixnum
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.10.11"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_cache_manager:
dependency: "direct main"
description:
name: flutter_cache_manager
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0-nullsafety.1"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
intl: http:
dependency: transitive dependency: transitive
description: description:
name: intl name: http
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.16.1" version: "0.13.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
json_annotation: json_annotation:
dependency: transitive dependency: transitive
description: description:
name: json_annotation name: json_annotation
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.1" version: "4.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.12.10-nullsafety.1" version: "0.12.10"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0"
okhttp_kit:
dependency: "direct main"
description:
name: okhttp_kit
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.2"
path: path:
dependency: "direct main" dependency: transitive
description: description:
name: path name: path
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.0-nullsafety.1" version: "1.8.0"
path_provider: path_provider:
dependency: "direct main" dependency: transitive
description: description:
name: path_provider name: path_provider
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.6.27" version: "2.0.1"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.0.1+2" version: "2.0.0"
path_provider_macos: path_provider_macos:
dependency: transitive dependency: transitive
description: description:
name: path_provider_macos name: path_provider_macos
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.0.4+8" version: "2.0.0"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.4" version: "2.0.1"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.0.4+3" version: "2.0.0"
pedantic: pedantic:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: pedantic name: pedantic
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.9.2" version: "1.11.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.0.2"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.2.1" version: "3.0.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.3" version: "2.0.0"
process: process:
dependency: transitive dependency: transitive
description: description:
name: process name: process
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.13" version: "4.1.0"
rxdart:
dependency: transitive
description:
name: rxdart
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.26.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -218,77 +239,112 @@ packages:
name: source_span name: source_span
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.0-nullsafety.2" version: "1.8.0"
sqflite:
dependency: transitive
description:
name: sqflite
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0+3"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0+2"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.10.0-nullsafety.1" version: "1.10.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.1" version: "2.1.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.1" version: "1.1.0"
synchronized:
dependency: transitive
description:
name: synchronized
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.0"
tencent_kit: tencent_kit:
dependency: "direct main" dependency: "direct main"
description: description:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "2.0.1" version: "2.1.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.19-nullsafety.2" version: "0.2.19"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.3" version: "2.1.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.7.4+1" version: "2.0.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.2" version: "0.2.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.2"
sdks: sdks:
dart: ">=2.10.0-110 <2.11.0" dart: ">=2.12.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0" flutter: ">=1.24.0-10"

View File

@ -1,12 +1,14 @@
name: tencent_kit_example name: tencent_kit_example
description: Demonstrates how to use the tencent_kit plugin. description: Demonstrates how to use the tencent_kit plugin.
version: 1.0.0+1000
# The following line prevents the package from being accidentally published to # 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 `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+100
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:
@ -22,12 +24,9 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3 cupertino_icons: ^1.0.2
path: ^1.6.4 flutter_cache_manager: ^3.0.0-nullsafety.1
path_provider: ^1.4.0
okhttp_kit: ^1.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -4,7 +4,7 @@
# #
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = 'tencent_kit' s.name = 'tencent_kit'
s.version = '2.0.1' s.version = '2.1.0'
s.summary = 'A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs.' s.summary = 'A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs.'
s.description = <<-DESC s.description = <<-DESC
A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs. A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs.

View File

@ -2,7 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
abstract class TencentApiResp { abstract class TencentApiResp {
const TencentApiResp({ const TencentApiResp({
this.ret, required this.ret,
this.msg, this.msg,
}); });
@ -14,7 +14,7 @@ abstract class TencentApiResp {
defaultValue: RET_SUCCESS, defaultValue: RET_SUCCESS,
) )
final int ret; final int ret;
final String msg; final String? msg;
bool get isSuccessful => ret == RET_SUCCESS; bool get isSuccessful => ret == RET_SUCCESS;
} }

View File

@ -9,8 +9,8 @@ part 'tencent_user_info_resp.g.dart';
) )
class TencentUserInfoResp extends TencentApiResp { class TencentUserInfoResp extends TencentApiResp {
const TencentUserInfoResp({ const TencentUserInfoResp({
int ret, required int ret,
String msg, String? msg,
this.isLost, this.isLost,
this.nickname, this.nickname,
this.gender, this.gender,
@ -36,58 +36,58 @@ class TencentUserInfoResp extends TencentApiResp {
factory TencentUserInfoResp.fromJson(Map<String, dynamic> json) => factory TencentUserInfoResp.fromJson(Map<String, dynamic> json) =>
_$TencentUserInfoRespFromJson(json); _$TencentUserInfoRespFromJson(json);
final int isLost; final int? isLost;
final String nickname; final String? nickname;
final String gender; // 男/女 final String? gender; // 男/女
final int genderType; // 男/女 - 1 final int? genderType; // 男/女 - 1
final String province; final String? province;
final String city; final String? city;
final String year; final String? year;
final String constellation; final String? constellation;
final String figureurl; final String? figureurl;
@JsonKey( @JsonKey(
name: 'figureurl_1', name: 'figureurl_1',
) )
final String figureurl1; final String? figureurl1;
@JsonKey( @JsonKey(
name: 'figureurl_2', name: 'figureurl_2',
) )
final String figureurl2; final String? figureurl2;
final String figureurlQq; // 140 * 140 final String? figureurlQq; // 140 * 140
@JsonKey( @JsonKey(
name: 'figureurl_qq_1', name: 'figureurl_qq_1',
) )
final String figureurlQq1; // 大小为40×40像素的QQ头像URL。 final String? figureurlQq1; // 大小为40×40像素的QQ头像URL。
@JsonKey( @JsonKey(
name: 'figureurl_qq_2', name: 'figureurl_qq_2',
) )
final String final String?
figureurlQq2; // 大小为100×100像素的QQ头像URL。需要注意不是所有的用户都拥有QQ的100x100的头像但40x40像素则是一定会有。 figureurlQq2; // 大小为100×100像素的QQ头像URL。需要注意不是所有的用户都拥有QQ的100x100的头像但40x40像素则是一定会有。
final String figureurlType; final String? figureurlType;
final String isYellowVip; final String? isYellowVip;
final String vip; final String? vip;
final String yellowVipLevel; final String? yellowVipLevel;
final String level; final String? level;
final String isYellowYearVip; final String? isYellowYearVip;
bool get isMale => gender == ''; bool get isMale => gender == '';
bool get isFemale => gender == ''; bool get isFemale => gender == '';
String get headImgUrl { String? get headImgUrl {
if (figureurlQq != null && figureurlQq.isNotEmpty) { if (figureurlQq?.isNotEmpty ?? false) {
return figureurlQq; return figureurlQq;
} }
if (figureurlQq2 != null && figureurlQq2.isNotEmpty) { if (figureurlQq2?.isNotEmpty ?? false) {
return figureurlQq2; return figureurlQq2;
} }
if (figureurlQq1 != null && figureurlQq1.isNotEmpty) { if (figureurlQq1?.isNotEmpty ?? false) {
return figureurlQq1; return figureurlQq1;
} }
if (figureurl2 != null && figureurl2.isNotEmpty) { if (figureurl2?.isNotEmpty ?? false) {
return figureurl2; return figureurl2;
} }
if (figureurl1 != null && figureurl1.isNotEmpty) { if (figureurl1?.isNotEmpty ?? false) {
return figureurl1; return figureurl1;
} }
return figureurl; return figureurl;

View File

@ -8,28 +8,28 @@ part of 'tencent_user_info_resp.dart';
TencentUserInfoResp _$TencentUserInfoRespFromJson(Map<String, dynamic> json) { TencentUserInfoResp _$TencentUserInfoRespFromJson(Map<String, dynamic> json) {
return TencentUserInfoResp( return TencentUserInfoResp(
ret: json['ret'] as int ?? 0, ret: json['ret'] as int? ?? 0,
msg: json['msg'] as String, msg: json['msg'] as String?,
isLost: json['is_lost'] as int, isLost: json['is_lost'] as int?,
nickname: json['nickname'] as String, nickname: json['nickname'] as String?,
gender: json['gender'] as String, gender: json['gender'] as String?,
genderType: json['gender_type'] as int, genderType: json['gender_type'] as int?,
province: json['province'] as String, province: json['province'] as String?,
city: json['city'] as String, city: json['city'] as String?,
year: json['year'] as String, year: json['year'] as String?,
constellation: json['constellation'] as String, constellation: json['constellation'] as String?,
figureurl: json['figureurl'] as String, figureurl: json['figureurl'] as String?,
figureurl1: json['figureurl_1'] as String, figureurl1: json['figureurl_1'] as String?,
figureurl2: json['figureurl_2'] as String, figureurl2: json['figureurl_2'] as String?,
figureurlQq: json['figureurl_qq'] as String, figureurlQq: json['figureurl_qq'] as String?,
figureurlQq1: json['figureurl_qq_1'] as String, figureurlQq1: json['figureurl_qq_1'] as String?,
figureurlQq2: json['figureurl_qq_2'] as String, figureurlQq2: json['figureurl_qq_2'] as String?,
figureurlType: json['figureurl_type'] as String, figureurlType: json['figureurl_type'] as String?,
isYellowVip: json['is_yellow_vip'] as String, isYellowVip: json['is_yellow_vip'] as String?,
vip: json['vip'] as String, vip: json['vip'] as String?,
yellowVipLevel: json['yellow_vip_level'] as String, yellowVipLevel: json['yellow_vip_level'] as String?,
level: json['level'] as String, level: json['level'] as String?,
isYellowYearVip: json['is_yellow_year_vip'] as String, isYellowYearVip: json['is_yellow_year_vip'] as String?,
); );
} }

View File

@ -9,8 +9,8 @@ part 'tencent_login_resp.g.dart';
) )
class TencentLoginResp extends TencentSdkResp { class TencentLoginResp extends TencentSdkResp {
const TencentLoginResp({ const TencentLoginResp({
int ret, required int ret,
String msg, String? msg,
this.openid, this.openid,
this.accessToken, this.accessToken,
this.expiresIn, this.expiresIn,
@ -20,13 +20,15 @@ class TencentLoginResp extends TencentSdkResp {
factory TencentLoginResp.fromJson(Map<String, dynamic> json) => factory TencentLoginResp.fromJson(Map<String, dynamic> json) =>
_$TencentLoginRespFromJson(json); _$TencentLoginRespFromJson(json);
final String openid; final String? openid;
final String accessToken; final String? accessToken;
final int expiresIn; final int? expiresIn;
final int createAt; final int? createAt;
bool get isExpired => bool? get isExpired => isSuccessful
DateTime.now().millisecondsSinceEpoch - createAt >= expiresIn * 1000; ? DateTime.now().millisecondsSinceEpoch - createAt! >= expiresIn! * 1000
: null;
@override
Map<String, dynamic> toJson() => _$TencentLoginRespToJson(this); Map<String, dynamic> toJson() => _$TencentLoginRespToJson(this);
} }

View File

@ -8,12 +8,12 @@ part of 'tencent_login_resp.dart';
TencentLoginResp _$TencentLoginRespFromJson(Map<String, dynamic> json) { TencentLoginResp _$TencentLoginRespFromJson(Map<String, dynamic> json) {
return TencentLoginResp( return TencentLoginResp(
ret: json['ret'] as int ?? 0, ret: json['ret'] as int? ?? 0,
msg: json['msg'] as String, msg: json['msg'] as String?,
openid: json['openid'] as String, openid: json['openid'] as String?,
accessToken: json['access_token'] as String, accessToken: json['access_token'] as String?,
expiresIn: json['expires_in'] as int, expiresIn: json['expires_in'] as int?,
createAt: json['create_at'] as int, createAt: json['create_at'] as int?,
); );
} }

View File

@ -1,11 +1,20 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
abstract class TencentSdkResp { part 'tencent_sdk_resp.g.dart';
@JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
)
class TencentSdkResp {
const TencentSdkResp({ const TencentSdkResp({
this.ret, required this.ret,
this.msg, this.msg,
}); });
factory TencentSdkResp.fromJson(Map<String, dynamic> json) =>
_$TencentSdkRespFromJson(json);
/// 网络请求成功发送至服务器,并且服务器返回数据格式正确 /// 网络请求成功发送至服务器,并且服务器返回数据格式正确
/// 这里包括所请求业务操作失败的情况,例如没有授权等原因导致 /// 这里包括所请求业务操作失败的情况,例如没有授权等原因导致
static const int RET_SUCCESS = 0; static const int RET_SUCCESS = 0;
@ -21,9 +30,11 @@ abstract class TencentSdkResp {
defaultValue: RET_SUCCESS, defaultValue: RET_SUCCESS,
) )
final int ret; final int ret;
final String msg; final String? msg;
bool get isSuccessful => ret == RET_SUCCESS; bool get isSuccessful => ret == RET_SUCCESS;
bool get isCancelled => ret == RET_USERCANCEL; bool get isCancelled => ret == RET_USERCANCEL;
Map<String, dynamic> toJson() => _$TencentSdkRespToJson(this);
} }

View File

@ -1,19 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tencent_share_resp.dart'; part of 'tencent_sdk_resp.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
TencentShareResp _$TencentShareRespFromJson(Map<String, dynamic> json) { TencentSdkResp _$TencentSdkRespFromJson(Map<String, dynamic> json) {
return TencentShareResp( return TencentSdkResp(
ret: json['ret'] as int ?? 0, ret: json['ret'] as int? ?? 0,
msg: json['msg'] as String, msg: json['msg'] as String?,
); );
} }
Map<String, dynamic> _$TencentShareRespToJson(TencentShareResp instance) => Map<String, dynamic> _$TencentSdkRespToJson(TencentSdkResp instance) =>
<String, dynamic>{ <String, dynamic>{
'ret': instance.ret, 'ret': instance.ret,
'msg': instance.msg, 'msg': instance.msg,

View File

@ -1,20 +0,0 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:tencent_kit/src/model/sdk/tencent_sdk_resp.dart';
part 'tencent_share_resp.g.dart';
@JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
)
class TencentShareResp extends TencentSdkResp {
const TencentShareResp({
int ret,
String msg,
}) : super(ret: ret, msg: msg);
factory TencentShareResp.fromJson(Map<String, dynamic> json) =>
_$TencentShareRespFromJson(json);
Map<String, dynamic> toJson() => _$TencentShareRespToJson(this);
}

View File

@ -8,7 +8,7 @@ part 'tencent_unionid_resp.g.dart';
) )
class TencentUnionidResp { class TencentUnionidResp {
const TencentUnionidResp({ const TencentUnionidResp({
this.error, required this.error,
this.errorDescription, this.errorDescription,
this.clientId, this.clientId,
this.openid, this.openid,
@ -22,10 +22,10 @@ class TencentUnionidResp {
defaultValue: ERROR_SUCCESS, defaultValue: ERROR_SUCCESS,
) )
final int error; final int error;
final String errorDescription; final String? errorDescription;
final String clientId; final String? clientId;
final String openid; final String? openid;
final String unionid; final String? unionid;
static const int ERROR_SUCCESS = 0; static const int ERROR_SUCCESS = 0;

View File

@ -8,11 +8,11 @@ part of 'tencent_unionid_resp.dart';
TencentUnionidResp _$TencentUnionidRespFromJson(Map<String, dynamic> json) { TencentUnionidResp _$TencentUnionidRespFromJson(Map<String, dynamic> json) {
return TencentUnionidResp( return TencentUnionidResp(
error: json['error'] as int ?? 0, error: json['error'] as int? ?? 0,
errorDescription: json['error_description'] as String, errorDescription: json['error_description'] as String?,
clientId: json['client_id'] as String, clientId: json['client_id'] as String?,
openid: json['openid'] as String, openid: json['openid'] as String?,
unionid: json['unionid'] as String, unionid: json['unionid'] as String?,
); );
} }

View File

@ -2,20 +2,21 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:tencent_kit/src/model/api/tencent_user_info_resp.dart'; import 'package:tencent_kit/src/model/api/tencent_user_info_resp.dart';
import 'package:tencent_kit/src/model/sdk/tencent_login_resp.dart'; import 'package:tencent_kit/src/model/sdk/tencent_login_resp.dart';
import 'package:tencent_kit/src/model/sdk/tencent_share_resp.dart'; import 'package:tencent_kit/src/model/sdk/tencent_sdk_resp.dart';
import 'package:tencent_kit/src/model/unionid/tencent_unionid_resp.dart'; import 'package:tencent_kit/src/model/unionid/tencent_unionid_resp.dart';
import 'package:tencent_kit/src/tencent_constant.dart'; import 'package:tencent_kit/src/tencent_constant.dart';
/// ///
class Tencent { class Tencent {
/// ///
Tencent() { Tencent._();
_channel.setMethodCallHandler(_handleMethod);
} static Tencent get instance => _instance;
static final Tencent _instance = Tencent._();
static const String _METHOD_REGISTERAPP = 'registerApp'; static const String _METHOD_REGISTERAPP = 'registerApp';
static const String _METHOD_ISQQINSTALLED = 'isQQInstalled'; static const String _METHOD_ISQQINSTALLED = 'isQQInstalled';
@ -47,14 +48,15 @@ class Tencent {
static const String _SCHEME_FILE = 'file'; static const String _SCHEME_FILE = 'file';
final MethodChannel _channel = late final MethodChannel _channel =
const MethodChannel('v7lin.github.io/tencent_kit'); const MethodChannel('v7lin.github.io/tencent_kit')
..setMethodCallHandler(_handleMethod);
final StreamController<TencentLoginResp> _loginRespStreamController = final StreamController<TencentLoginResp> _loginRespStreamController =
StreamController<TencentLoginResp>.broadcast(); StreamController<TencentLoginResp>.broadcast();
final StreamController<TencentShareResp> _shareRespStreamController = final StreamController<TencentSdkResp> _shareRespStreamController =
StreamController<TencentShareResp>.broadcast(); StreamController<TencentSdkResp>.broadcast();
Future<dynamic> _handleMethod(MethodCall call) async { Future<dynamic> _handleMethod(MethodCall call) async {
switch (call.method) { switch (call.method) {
@ -63,7 +65,7 @@ class Tencent {
(call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>())); (call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>()));
break; break;
case _METHOD_ONSHARERESP: case _METHOD_ONSHARERESP:
_shareRespStreamController.add(TencentShareResp.fromJson( _shareRespStreamController.add(TencentSdkResp.fromJson(
(call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>())); (call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>()));
break; break;
} }
@ -71,10 +73,9 @@ class Tencent {
/// 向 Open_SDK 注册 /// 向 Open_SDK 注册
Future<void> registerApp({ Future<void> registerApp({
@required String appId, required String appId,
String universalLink, String? universalLink,
}) { }) {
assert(appId?.isNotEmpty ?? false);
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_REGISTERAPP, _METHOD_REGISTERAPP,
<String, dynamic>{ <String, dynamic>{
@ -91,25 +92,24 @@ class Tencent {
} }
/// 分享 /// 分享
Stream<TencentShareResp> shareResp() { Stream<TencentSdkResp> shareResp() {
return _shareRespStreamController.stream; return _shareRespStreamController.stream;
} }
/// 检查QQ是否已安装 /// 检查QQ是否已安装
Future<bool> isQQInstalled() { Future<bool> isQQInstalled() async {
return _channel.invokeMethod<bool>(_METHOD_ISQQINSTALLED); return await _channel.invokeMethod<bool>(_METHOD_ISQQINSTALLED) ?? false;
} }
/// 检查QQ是否已安装 /// 检查QQ是否已安装
Future<bool> isTIMInstalled() { Future<bool> isTIMInstalled() async {
return _channel.invokeMethod<bool>(_METHOD_ISTIMINSTALLED); return await _channel.invokeMethod<bool>(_METHOD_ISTIMINSTALLED) ?? false;
} }
/// 登录 /// 登录
Future<void> login({ Future<void> login({
@required List<String> scope, required List<String> scope,
}) { }) {
assert(scope?.isNotEmpty ?? false);
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_LOGIN, _METHOD_LOGIN,
<String, dynamic>{ <String, dynamic>{
@ -126,13 +126,10 @@ class Tencent {
/// 用户信息 /// 用户信息
/// https://wiki.connect.qq.com/get_user_info /// https://wiki.connect.qq.com/get_user_info
Future<TencentUserInfoResp> getUserInfo({ Future<TencentUserInfoResp> getUserInfo({
@required String appId, required String appId,
@required String openid, required String openid,
@required String accessToken, required String accessToken,
}) { }) {
assert(appId?.isNotEmpty ?? false);
assert(openid?.isNotEmpty ?? false);
assert(accessToken?.isNotEmpty ?? false);
return HttpClient() return HttpClient()
.getUrl(Uri.parse( .getUrl(Uri.parse(
'https://graph.qq.com/user/get_user_info?access_token=$accessToken&oauth_consumer_key=$appId&openid=$openid')) 'https://graph.qq.com/user/get_user_info?access_token=$accessToken&oauth_consumer_key=$appId&openid=$openid'))
@ -140,9 +137,10 @@ class Tencent {
return request.close(); return request.close();
}).then((HttpClientResponse response) async { }).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) { if (response.statusCode == HttpStatus.ok) {
ContentType contentType = response.headers.contentType; final ContentType? contentType = response.headers.contentType;
Encoding encoding = Encoding.getByName(contentType?.charset) ?? utf8; final Encoding encoding =
String content = await encoding.decodeStream(response); Encoding.getByName(contentType?.charset) ?? utf8;
final String content = await encoding.decodeStream(response);
return TencentUserInfoResp.fromJson( return TencentUserInfoResp.fromJson(
json.decode(content) as Map<String, dynamic>); json.decode(content) as Map<String, dynamic>);
} }
@ -154,10 +152,9 @@ class Tencent {
/// UnionID /// UnionID
/// https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D /// https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D
Future<TencentUnionidResp> getUnionId({ Future<TencentUnionidResp> getUnionId({
@required String accessToken, required String accessToken,
String unionid = '1', String unionid = '1',
}) { }) {
assert(accessToken?.isNotEmpty ?? false);
return HttpClient() return HttpClient()
.getUrl(Uri.parse( .getUrl(Uri.parse(
'https://graph.qq.com/oauth2.0/me?access_token=$accessToken&unionid=$unionid')) 'https://graph.qq.com/oauth2.0/me?access_token=$accessToken&unionid=$unionid'))
@ -165,18 +162,21 @@ class Tencent {
return request.close(); return request.close();
}).then((HttpClientResponse response) async { }).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) { if (response.statusCode == HttpStatus.ok) {
ContentType contentType = response.headers.contentType; final ContentType? contentType = response.headers.contentType;
Encoding encoding = Encoding.getByName(contentType?.charset) ?? utf8; final Encoding encoding =
String callback = await encoding.decodeStream(response); Encoding.getByName(contentType?.charset) ?? utf8;
final String callback = await encoding.decodeStream(response);
// 腾讯有毒 callback( $json ); // 腾讯有毒 callback( $json );
RegExp exp = RegExp(r'callback\( (.*) \)\;'); final RegExp exp = RegExp(r'callback\( (.*) \)\;');
Match match = exp.firstMatch(callback); final Match? match = exp.firstMatch(callback);
if (match.groupCount == 1) { if (match?.groupCount == 1) {
String content = match.group(1); final String? content = match!.group(1);
if (content != null) {
return TencentUnionidResp.fromJson( return TencentUnionidResp.fromJson(
json.decode(content) as Map<String, dynamic>); json.decode(content) as Map<String, dynamic>);
} }
} }
}
throw HttpException( throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
}); });
@ -184,18 +184,17 @@ class Tencent {
/// 分享 - 说说 /// 分享 - 说说
Future<void> shareMood({ Future<void> shareMood({
@required int scene, required int scene,
String summary, String? summary,
List<Uri> imageUris, List<Uri>? imageUris,
Uri videoUri, Uri? videoUri,
}) { }) {
assert(scene == TencentScene.SCENE_QZONE); assert(scene == TencentScene.SCENE_QZONE);
assert((summary?.isNotEmpty ?? false) || assert((summary?.isNotEmpty ?? false) ||
(imageUris?.isNotEmpty ?? false) ||
(videoUri != null && videoUri.isScheme(_SCHEME_FILE)) ||
((imageUris?.isNotEmpty ?? false) && ((imageUris?.isNotEmpty ?? false) &&
imageUris.every((Uri element) => imageUris!
element != null && element.isScheme(_SCHEME_FILE)))); .every((Uri element) => element.isScheme(_SCHEME_FILE))) ||
(videoUri != null && videoUri.isScheme(_SCHEME_FILE)));
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_SHAREMOOD, _METHOD_SHAREMOOD,
<String, dynamic>{ <String, dynamic>{
@ -203,7 +202,7 @@ class Tencent {
if (summary?.isNotEmpty ?? false) _ARGUMENT_KEY_SUMMARY: summary, if (summary?.isNotEmpty ?? false) _ARGUMENT_KEY_SUMMARY: summary,
if (imageUris?.isNotEmpty ?? false) if (imageUris?.isNotEmpty ?? false)
_ARGUMENT_KEY_IMAGEURIS: _ARGUMENT_KEY_IMAGEURIS:
imageUris.map((Uri imageUri) => imageUri.toString()).toList(), imageUris!.map((Uri imageUri) => imageUri.toString()).toList(),
if (videoUri != null) _ARGUMENT_KEY_VIDEOURI: videoUri.toString(), if (videoUri != null) _ARGUMENT_KEY_VIDEOURI: videoUri.toString(),
}, },
); );
@ -211,11 +210,10 @@ class Tencent {
/// 分享 - 文本Android调用的是系统API故而不会有回调 /// 分享 - 文本Android调用的是系统API故而不会有回调
Future<void> shareText({ Future<void> shareText({
@required int scene, required int scene,
@required String summary, required String summary,
}) { }) {
assert(scene == TencentScene.SCENE_QQ); assert(scene == TencentScene.SCENE_QQ);
assert(summary?.isNotEmpty ?? false);
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_SHARETEXT, _METHOD_SHARETEXT,
<String, dynamic>{ <String, dynamic>{
@ -227,13 +225,13 @@ class Tencent {
/// 分享 - 图片 /// 分享 - 图片
Future<void> shareImage({ Future<void> shareImage({
@required int scene, required int scene,
@required Uri imageUri, required Uri imageUri,
String appName, String? appName,
int extInt = TencentQZoneFlag.DEFAULT, int extInt = TencentQZoneFlag.DEFAULT,
}) { }) {
assert(scene == TencentScene.SCENE_QQ); assert(scene == TencentScene.SCENE_QQ);
assert(imageUri != null && imageUri.isScheme(_SCHEME_FILE)); assert(imageUri.isScheme(_SCHEME_FILE));
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_SHAREIMAGE, _METHOD_SHAREIMAGE,
<String, dynamic>{ <String, dynamic>{
@ -247,19 +245,16 @@ class Tencent {
/// 分享 - 音乐 /// 分享 - 音乐
Future<void> shareMusic({ Future<void> shareMusic({
@required int scene, required int scene,
@required String title, required String title,
String summary, String? summary,
Uri imageUri, Uri? imageUri,
@required String musicUrl, required String musicUrl,
@required String targetUrl, required String targetUrl,
String appName, String? appName,
int extInt = TencentQZoneFlag.DEFAULT, int extInt = TencentQZoneFlag.DEFAULT,
}) { }) {
assert(scene == TencentScene.SCENE_QQ); assert(scene == TencentScene.SCENE_QQ);
assert(title?.isNotEmpty ?? false);
assert(musicUrl?.isNotEmpty ?? false);
assert(targetUrl?.isNotEmpty ?? false);
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_SHAREMUSIC, _METHOD_SHAREMUSIC,
<String, dynamic>{ <String, dynamic>{
@ -277,16 +272,14 @@ class Tencent {
/// 分享 - 网页 /// 分享 - 网页
Future<void> shareWebpage({ Future<void> shareWebpage({
@required int scene, required int scene,
@required String title, required String title,
String summary, String? summary,
Uri imageUri, Uri? imageUri,
@required String targetUrl, required String targetUrl,
String appName, String? appName,
int extInt = TencentQZoneFlag.DEFAULT, int extInt = TencentQZoneFlag.DEFAULT,
}) { }) {
assert(title?.isNotEmpty ?? false);
assert(targetUrl?.isNotEmpty ?? false);
return _channel.invokeMethod<void>( return _channel.invokeMethod<void>(
_METHOD_SHAREWEBPAGE, _METHOD_SHAREWEBPAGE,
<String, dynamic>{ <String, dynamic>{

View File

@ -1,5 +1,5 @@
class TencentScope { class TencentScope {
TencentScope._(); const TencentScope._();
/// 发表一条说说到QQ空间(需要申请权限) /// 发表一条说说到QQ空间(需要申请权限)
static const String OPEN_PERMISSION_ADD_TOPIC = 'add_topic'; static const String OPEN_PERMISSION_ADD_TOPIC = 'add_topic';
@ -45,7 +45,7 @@ class TencentScope {
} }
class TencentScene { class TencentScene {
TencentScene._(); const TencentScene._();
/// QQ /// QQ
static const int SCENE_QQ = 0; static const int SCENE_QQ = 0;
@ -55,7 +55,7 @@ class TencentScene {
} }
class TencentQZoneFlag { class TencentQZoneFlag {
TencentQZoneFlag._(); const TencentQZoneFlag._();
/// 默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框 /// 默认是不隐藏分享到QZone按钮且不自动打开分享到QZone的对话框
static const int DEFAULT = 0; static const int DEFAULT = 0;

View File

@ -4,7 +4,6 @@ export 'src/model/api/tencent_api_resp.dart';
export 'src/model/api/tencent_user_info_resp.dart'; export 'src/model/api/tencent_user_info_resp.dart';
export 'src/model/sdk/tencent_login_resp.dart'; export 'src/model/sdk/tencent_login_resp.dart';
export 'src/model/sdk/tencent_sdk_resp.dart'; export 'src/model/sdk/tencent_sdk_resp.dart';
export 'src/model/sdk/tencent_share_resp.dart';
export 'src/model/unionid/tencent_unionid_resp.dart'; export 'src/model/unionid/tencent_unionid_resp.dart';
export 'src/tencent.dart'; export 'src/tencent.dart';
export 'src/tencent_constant.dart'; export 'src/tencent_constant.dart';

View File

@ -7,189 +7,182 @@ packages:
name: _fe_analyzer_shared name: _fe_analyzer_shared
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "14.0.0" version: "18.0.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.41.2" version: "1.2.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.6.0" version: "2.0.0"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.5.0-nullsafety.1" version: "2.5.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.1" version: "2.1.0"
build: build:
dependency: transitive dependency: transitive
description: description:
name: build name: build
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.6.1" version: "2.0.0"
build_config: build_config:
dependency: transitive dependency: transitive
description: description:
name: build_config name: build_config
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.4.5" version: "0.4.7"
build_daemon: build_daemon:
dependency: transitive dependency: transitive
description: description:
name: build_daemon name: build_daemon
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.6" version: "2.1.10"
build_resolvers: build_resolvers:
dependency: transitive dependency: transitive
description: description:
name: build_resolvers name: build_resolvers
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.5.2" version: "2.0.0"
build_runner: build_runner:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: build_runner name: build_runner
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.11.0" version: "1.12.2"
build_runner_core: build_runner_core:
dependency: transitive dependency: transitive
description: description:
name: build_runner_core name: build_runner_core
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.1.6" version: "6.1.12"
built_collection: built_collection:
dependency: transitive dependency: transitive
description: description:
name: built_collection name: built_collection
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.3.2" version: "5.0.0"
built_value: built_value:
dependency: transitive dependency: transitive
description: description:
name: built_value name: built_value
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "7.1.0" version: "8.0.3"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.3" version: "1.1.0"
charcode: charcode:
dependency: transitive dependency: transitive
description: description:
name: charcode name: charcode
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
checked_yaml: checked_yaml:
dependency: transitive dependency: transitive
description: description:
name: checked_yaml name: checked_yaml
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.4" version: "2.0.1"
cli_util: cli_util:
dependency: transitive dependency: transitive
description: description:
name: cli_util name: cli_util
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.0" version: "0.3.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.1" version: "1.1.0"
code_builder: code_builder:
dependency: transitive dependency: transitive
description: description:
name: code_builder name: code_builder
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.6.0" version: "3.7.0"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.15.0-nullsafety.3" version: "1.15.0"
convert: convert:
dependency: transitive dependency: transitive
description: description:
name: convert name: convert
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.1" version: "3.0.0"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.5" version: "3.0.0"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
name: dart_style name: dart_style
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.11" version: "1.3.14"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.3"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "5.2.1" version: "6.1.0"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
name: fixnum name: fixnum
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.10.11" version: "1.0.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -206,231 +199,140 @@ packages:
name: glob name: glob
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0" version: "2.0.0"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:
name: graphs name: graphs
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.0" version: "1.0.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
name: http_multi_server name: http_multi_server
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.2.0" version: "3.0.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.4" version: "4.0.0"
intl:
dependency: transitive
description:
name: intl
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.16.1"
io: io:
dependency: transitive dependency: transitive
description: description:
name: io name: io
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.3.4" version: "1.0.0"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.6.2" version: "0.6.3"
json_annotation: json_annotation:
dependency: "direct main" dependency: "direct main"
description: description:
name: json_annotation name: json_annotation
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.1.1" version: "4.0.0"
json_serializable: json_serializable:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: json_serializable name: json_serializable
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.5.1" version: "4.0.3"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.11.4" version: "1.0.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.12.10-nullsafety.1" version: "0.12.10"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.9.7" version: "1.0.0"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
okhttp_kit:
dependency: "direct dev"
description:
name: okhttp_kit
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.2"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
name: package_config name: package_config
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.9.3" version: "2.0.0"
path: path:
dependency: "direct dev" dependency: transitive
description: description:
name: path name: path
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.0-nullsafety.1" version: "1.8.0"
path_provider:
dependency: "direct dev"
description:
name: path_provider
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.6.27"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.1+2"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.4+8"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.4"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.4+3"
pedantic: pedantic:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: pedantic name: pedantic
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.9.2" version: "1.11.0"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.2.1"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
pool: pool:
dependency: transitive dependency: transitive
description: description:
name: pool name: pool
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.4.0" version: "1.5.0"
process:
dependency: transitive
description:
name: process
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.13"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:
name: pub_semver name: pub_semver
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.4.4" version: "2.0.0"
pubspec_parse: pubspec_parse:
dependency: transitive dependency: transitive
description: description:
name: pubspec_parse name: pubspec_parse
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.7" version: "1.0.0"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.5"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
name: shelf name: shelf
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.7.9" version: "1.1.0"
shelf_web_socket: shelf_web_socket:
dependency: transitive dependency: transitive
description: description:
name: shelf_web_socket name: shelf_web_socket
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.4" version: "1.0.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -442,112 +344,98 @@ packages:
name: source_gen name: source_gen
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.9.10+1" version: "0.9.10+4"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.0-nullsafety.2" version: "1.8.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.10.0-nullsafety.1" version: "1.10.0"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.1" version: "2.1.0"
stream_transform: stream_transform:
dependency: transitive dependency: transitive
description: description:
name: stream_transform name: stream_transform
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0" version: "2.0.0"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0-nullsafety.1" version: "1.1.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0-nullsafety.1" version: "1.2.0"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.19-nullsafety.2" version: "0.2.19"
timing: timing:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.1.1+3" version: "1.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0-nullsafety.3" version: "1.3.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.0-nullsafety.3" version: "2.1.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
name: watcher name: watcher
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.9.7+15" version: "1.0.0"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
name: web_socket_channel name: web_socket_channel
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0" version: "2.0.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.4+1"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.1.2"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.2.1" version: "3.1.0"
sdks: sdks:
dart: ">=2.10.0 <2.11.0" dart: ">=2.12.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0" flutter: ">=1.20.0"

View File

@ -1,28 +1,23 @@
name: tencent_kit name: tencent_kit
description: A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs. description: A powerful Flutter plugin allowing developers to auth/share with natvie Android & iOS Tencent SDKs.
version: 2.0.1 version: 2.1.0
# author: v7lin <v7lin@qq.com> # author: v7lin <v7lin@qq.com>
homepage: https://github.com/v7lin/fake_tencent homepage: https://github.com/v7lin/fake_tencent
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.10.0" flutter: ">=1.20.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
json_annotation: '>=2.0.0 <4.0.0' json_annotation: ^4.0.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
path: ^1.6.4
path_provider: ^1.4.0
okhttp_kit: ^1.0.0
pedantic: pedantic:
build_runner: build_runner:

View File

@ -10,7 +10,6 @@ void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
const MethodChannel channel = MethodChannel('v7lin.github.io/tencent_kit'); const MethodChannel channel = MethodChannel('v7lin.github.io/tencent_kit');
final Tencent tencent = Tencent();
setUp(() { setUp(() {
channel.setMockMethodCallHandler((MethodCall call) async { channel.setMockMethodCallHandler((MethodCall call) async {
@ -26,7 +25,7 @@ void main() {
channel.name, channel.name,
channel.codec.encodeMethodCall( channel.codec.encodeMethodCall(
MethodCall('onLoginResp', json.decode('{"ret":-2}'))), MethodCall('onLoginResp', json.decode('{"ret":-2}'))),
(ByteData data) { (ByteData? data) {
// mock success // mock success
}, },
)); ));
@ -42,7 +41,7 @@ void main() {
channel.name, channel.name,
channel.codec.encodeMethodCall( channel.codec.encodeMethodCall(
MethodCall('onShareResp', json.decode('{"ret":0}'))), MethodCall('onShareResp', json.decode('{"ret":0}'))),
(ByteData data) { (ByteData? data) {
// mock success // mock success
}, },
)); ));
@ -57,30 +56,30 @@ void main() {
}); });
test('isQQInstalled', () async { test('isQQInstalled', () async {
expect(await tencent.isQQInstalled(), true); expect(await Tencent.instance.isQQInstalled(), true);
}); });
test('isTIMInstalled', () async { test('isTIMInstalled', () async {
expect(await tencent.isTIMInstalled(), true); expect(await Tencent.instance.isTIMInstalled(), true);
}); });
test('login', () async { test('login', () async {
StreamSubscription<TencentLoginResp> sub = final StreamSubscription<TencentLoginResp> sub =
tencent.loginResp().listen((TencentLoginResp resp) { Tencent.instance.loginResp().listen((TencentLoginResp resp) {
expect(resp.ret, TencentSdkResp.RET_USERCANCEL); expect(resp.ret, TencentSdkResp.RET_USERCANCEL);
}); });
await tencent.login( await Tencent.instance.login(
scope: <String>[TencentScope.GET_SIMPLE_USERINFO], scope: <String>[TencentScope.GET_SIMPLE_USERINFO],
); );
await sub.cancel(); await sub.cancel();
}); });
test('share', () async { test('share', () async {
StreamSubscription<TencentShareResp> sub = final StreamSubscription<TencentSdkResp> sub =
tencent.shareResp().listen((TencentShareResp resp) { Tencent.instance.shareResp().listen((TencentSdkResp resp) {
expect(resp.ret, TencentSdkResp.RET_SUCCESS); expect(resp.ret, TencentSdkResp.RET_SUCCESS);
}); });
await tencent.shareMood( await Tencent.instance.shareMood(
scene: TencentScene.SCENE_QZONE, scene: TencentScene.SCENE_QZONE,
summary: 'share text', summary: 'share text',
); );