From 9514a79f6a083854b9343061edb419e16ba00d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=89=E9=BB=98=E7=9A=84=E6=B9=AE=E7=81=B0?= Date: Mon, 22 Jun 2020 22:29:21 +0800 Subject: [PATCH] v2 (#22) v2 --- .drone.yml | 89 +-- .gitignore | 2 +- .metadata | 2 +- CHANGELOG.md | 4 + README.md | 90 ++- analysis_options.yaml | 305 ++++++---- android/build.gradle | 17 +- android/checkstyle.xml | 135 +++++ android/consumer-proguard-rules.txt | 1 - android/consumer-rules.pro | 4 + android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + android/quality.gradle | 17 + android/settings.gradle | 2 +- android/src/main/AndroidManifest.xml | 7 +- .../v7lin/fakeweibo/FakeWeiboPlugin.java | 259 --------- .../io/github/v7lin/weibo_kit/WeiboKit.java | 274 +++++++++ .../v7lin/weibo_kit/WeiboKitPlugin.java | 76 +++ example/.gitignore | 54 +- example/.metadata | 2 +- example/README.md | 12 +- example/analysis_options.yaml | 34 +- example/android/.gitignore | 7 + example/android/app/build.gradle | 14 +- example/android/app/proguard-rules.pro | 8 - .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 40 +- .../v7lin/fakeweiboexample/MainActivity.java | 13 - .../v7lin/weibo_kit_example/MainActivity.java | 6 + .../app/src/main/res/values/styles.xml | 10 + .../app/src/profile/AndroidManifest.xml | 7 + example/android/build.gradle | 2 +- example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle | 22 +- example/images/icon/2.0x/ic_launcher.png | Bin 721 -> 0 bytes example/images/icon/2.0x/timg.jpeg | Bin 105374 -> 0 bytes example/ios/.gitignore | 32 + example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Podfile | 83 +-- example/ios/Podfile.lock | 50 ++ example/ios/Runner.xcodeproj/project.pbxproj | 132 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 4 +- example/ios/Runner/AppDelegate.m | 4 +- .../Icon-App-1024x1024@1x.png | Bin 11112 -> 10932 bytes example/ios/Runner/Info.plist | 66 ++- example/lib/main.dart | 93 ++- example/pubspec.lock | 287 +++++++++ example/pubspec.yaml | 43 +- ios/.gitignore | 1 + ios/Classes/FakeWeiboPlugin.h | 4 - ios/Classes/WeiboKitPlugin.h | 4 + .../{FakeWeiboPlugin.m => WeiboKitPlugin.m} | 57 +- ios/fake_weibo.podspec | 24 - ios/weibo_kit.podspec | 28 + lib/fake_weibo.dart | 9 - .../domain/api/weibo_user_info_resp.jser.dart | 54 -- lib/src/domain/sdk/weibo_auth_resp.dart | 24 - lib/src/domain/sdk/weibo_auth_resp.jser.dart | 38 -- lib/src/domain/sdk/weibo_sdk_resp.jser.dart | 28 - .../{domain => model}/api/weibo_api_resp.dart | 0 .../api/weibo_user_info_resp.dart | 20 +- lib/src/model/api/weibo_user_info_resp.g.dart | 42 ++ lib/src/model/sdk/weibo_auth_resp.dart | 30 + lib/src/model/sdk/weibo_auth_resp.g.dart | 28 + .../{domain => model}/sdk/weibo_sdk_resp.dart | 20 +- lib/src/model/sdk/weibo_sdk_resp.g.dart | 20 + lib/src/weibo.dart | 67 +-- .../{weibo_scope.dart => weibo_constant.dart} | 0 lib/weibo_kit.dart | 8 + pubspec.lock | 546 ++++++++++++++++++ pubspec.yaml | 44 +- test/fake_weibo_test.dart | 1 - test/jaguar_test.dart | 47 -- test/weibo_kit_test.dart | 79 +++ 75 files changed, 2499 insertions(+), 1055 deletions(-) mode change 100644 => 100755 .drone.yml mode change 100644 => 100755 analysis_options.yaml create mode 100644 android/checkstyle.xml delete mode 100644 android/consumer-proguard-rules.txt create mode 100644 android/consumer-rules.pro create mode 100644 android/gradle/wrapper/gradle-wrapper.properties create mode 100644 android/quality.gradle delete mode 100644 android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java create mode 100644 android/src/main/java/io/github/v7lin/weibo_kit/WeiboKit.java create mode 100644 android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java mode change 100644 => 100755 example/analysis_options.yaml create mode 100644 example/android/.gitignore delete mode 100644 example/android/app/proguard-rules.pro create mode 100644 example/android/app/src/debug/AndroidManifest.xml delete mode 100644 example/android/app/src/main/java/io/github/v7lin/fakeweiboexample/MainActivity.java create mode 100644 example/android/app/src/main/java/io/github/v7lin/weibo_kit_example/MainActivity.java create mode 100644 example/android/app/src/profile/AndroidManifest.xml delete mode 100644 example/images/icon/2.0x/ic_launcher.png delete mode 100644 example/images/icon/2.0x/timg.jpeg create mode 100644 example/ios/.gitignore create mode 100644 example/ios/Podfile.lock create mode 100644 example/pubspec.lock delete mode 100644 ios/Classes/FakeWeiboPlugin.h create mode 100644 ios/Classes/WeiboKitPlugin.h rename ios/Classes/{FakeWeiboPlugin.m => WeiboKitPlugin.m} (80%) delete mode 100644 ios/fake_weibo.podspec create mode 100644 ios/weibo_kit.podspec delete mode 100644 lib/fake_weibo.dart delete mode 100644 lib/src/domain/api/weibo_user_info_resp.jser.dart delete mode 100644 lib/src/domain/sdk/weibo_auth_resp.dart delete mode 100644 lib/src/domain/sdk/weibo_auth_resp.jser.dart delete mode 100644 lib/src/domain/sdk/weibo_sdk_resp.jser.dart rename lib/src/{domain => model}/api/weibo_api_resp.dart (100%) rename lib/src/{domain => model}/api/weibo_user_info_resp.dart (70%) create mode 100644 lib/src/model/api/weibo_user_info_resp.g.dart create mode 100644 lib/src/model/sdk/weibo_auth_resp.dart create mode 100644 lib/src/model/sdk/weibo_auth_resp.g.dart rename lib/src/{domain => model}/sdk/weibo_sdk_resp.dart (70%) create mode 100644 lib/src/model/sdk/weibo_sdk_resp.g.dart rename lib/src/{weibo_scope.dart => weibo_constant.dart} (100%) create mode 100644 lib/weibo_kit.dart create mode 100644 pubspec.lock delete mode 100644 test/fake_weibo_test.dart delete mode 100644 test/jaguar_test.dart create mode 100644 test/weibo_kit_test.dart diff --git a/.drone.yml b/.drone.yml old mode 100644 new mode 100755 index 1061906..d944647 --- a/.drone.yml +++ b/.drone.yml @@ -3,7 +3,7 @@ name: default steps: - name: prepare - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -11,15 +11,33 @@ steps: - flutter packages get #- name: build_runner -# image: v7lin/flutter:1.9.1-hotfix.2-stable +# image: v7lin/flutter:1.17.3-stable # volumes: # - name: pub-cache # path: /opt/flutter/.pub-cache # commands: -# - flutter packages pub run build_runner build +# - 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" +#- name: ios-format +# image: v7lin/clang +# commands: +# - cd ios/ +# - clang-format -style=file -i src/Classes/*.h src/Classes/*.m - name: format - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -27,7 +45,7 @@ steps: - flutter format --dry-run --set-exit-if-changed . - name: analyze - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -35,17 +53,17 @@ steps: - flutter analyze - name: test - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache commands: - - flutter test --coverage - - cd example/ - flutter test +# - cd example/ +# - flutter test - name: proguard - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -55,20 +73,20 @@ steps: - cd example/ - flutter build apk -- name: coverage - image: plugins/codecov:2.0.3 - settings: - token: - from_secret: CODECOV_TOKEN - files: - - ./coverage/lcov.info - when: - event: - exclude: - - pull_request +#- name: coverage +# image: plugins/codecov:2.0.3 +# settings: +# token: +# from_secret: CODECOV_TOKEN +# files: +# - ./coverage/lcov.info +# when: +# event: +# exclude: +# - pull_request - name: publish-check - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -91,10 +109,9 @@ steps: volumes: - name: pub-cache path: /opt/flutter/.pub-cache - environment: - PUB_CACHE: /opt/flutter/.pub-cache commands: - - wget -P $PUB_CACHE https://raw.githubusercontent.com/v7lin/pub_credentials/master/credentials.json.enc + - FLUTTER_HOME=/opt/flutter/.pub-cache + - wget -P $FLUTTER_HOME https://raw.githubusercontent.com/v7lin/pub_credentials/master/credentials.json.enc - name: restore-cache-openssl image: v7lin/openssl:1.1.1b @@ -102,17 +119,17 @@ steps: - name: pub-cache path: /opt/flutter/.pub-cache environment: - PUB_CACHE: /opt/flutter/.pub-cache ENC_METHOD: from_secret: ENC_METHOD ENC_PASSWORD: from_secret: ENC_PASSWORD commands: - - openssl enc -d -$ENC_METHOD -k $ENC_PASSWORD -in $PUB_CACHE/credentials.json.enc -out $PUB_CACHE/credentials.json - - rm $PUB_CACHE/credentials.json.enc + - FLUTTER_HOME=/opt/flutter/.pub-cache + - openssl enc -d -$ENC_METHOD -k $ENC_PASSWORD -in $FLUTTER_HOME/credentials.json.enc -out $FLUTTER_HOME/credentials.json + - rm $FLUTTER_HOME/credentials.json.enc - name: publish - image: v7lin/flutter:1.9.1-hotfix.2-stable + image: v7lin/flutter:1.17.3-stable volumes: - name: pub-cache path: /opt/flutter/.pub-cache @@ -125,14 +142,14 @@ steps: - name: pub-cache path: /opt/flutter/.pub-cache environment: - PUB_CACHE: /opt/flutter/.pub-cache ENC_METHOD: from_secret: ENC_METHOD ENC_PASSWORD: from_secret: ENC_PASSWORD commands: - - openssl enc -e -$ENC_METHOD -k $ENC_PASSWORD -in $PUB_CACHE/credentials.json -out $PUB_CACHE/credentials.json.enc - - rm $PUB_CACHE/credentials.json + - FLUTTER_HOME=/opt/flutter/.pub-cache + - openssl enc -e -$ENC_METHOD -k $ENC_PASSWORD -in $FLUTTER_HOME/credentials.json -out $FLUTTER_HOME/credentials.json.enc + - rm /opt/flutter/.pub-cache/credentials.json - name: save-cache image: docker:git @@ -140,7 +157,6 @@ steps: - name: pub-cache path: /opt/flutter/.pub-cache environment: - PUB_CACHE: /opt/flutter/.pub-cache GIT_USER_EMAIL: from_secret: GIT_USER_EMAIL GIT_USER_NAME: @@ -148,13 +164,14 @@ steps: GIT_USER_PASSWORD: from_secret: GIT_USER_PASSWORD # 密码含'@',用'%40'替换 -> URLEncoder.encode("@","utf-8"); commands: + - FLUTTER_HOME=/opt/flutter/.pub-cache - git config --global user.email $GIT_USER_EMAIL - git config --global user.name $GIT_USER_NAME - git config --global credential.helper store - - git clone -b master https://$GIT_USER_NAME:$GIT_USER_PASSWORD@github.com/v7lin/pub_credentials.git $PUB_CACHE/pub_credentials - - rm $PUB_CACHE/pub_credentials/credentials.json.enc - - mv $PUB_CACHE/credentials.json.enc $PUB_CACHE/pub_credentials/credentials.json.enc - - cd $PUB_CACHE/pub_credentials + - git clone -b master https://$GIT_USER_NAME:$GIT_USER_PASSWORD@github.com/v7lin/pub_credentials.git $FLUTTER_HOME/pub_credentials + - rm $FLUTTER_HOME/pub_credentials/credentials.json.enc + - mv $FLUTTER_HOME/credentials.json.enc $FLUTTER_HOME/pub_credentials/credentials.json.enc + - cd $FLUTTER_HOME/pub_credentials - git commit -am "update credentials by ci/cd tools" - git push diff --git a/.gitignore b/.gitignore index c9e2ce8..5f2e1f4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,9 @@ .packages .pub/ -pubspec.lock build/ +# custom .idea/ *.iml diff --git a/.metadata b/.metadata index 2517d63..53b454c 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b + revision: b041144f833e05cf463b8887fa12efdec9493488 channel: stable project_type: plugin diff --git a/CHANGELOG.md b/CHANGELOG.md index dff1ebc..40d24dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.0 - 2020.6.18 + +* 升级 Android/iOS SDK + ## 0.2.4 - 2019.9.26 * 降级Android SDK diff --git a/README.md b/README.md index 109fb0e..8d4c7de 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# fake_weibo +# weibo_kit [![Build Status](https://cloud.drone.io/api/badges/v7lin/fake_weibo/status.svg)](https://cloud.drone.io/v7lin/fake_weibo) [![Codecov](https://codecov.io/gh/v7lin/fake_weibo/branch/master/graph/badge.svg)](https://codecov.io/gh/v7lin/fake_weibo) [![GitHub Tag](https://img.shields.io/github/tag/v7lin/fake_weibo.svg)](https://github.com/v7lin/fake_weibo/releases) -[![Pub Package](https://img.shields.io/pub/v/fake_weibo.svg)](https://pub.dartlang.org/packages/fake_weibo) +[![Pub Package](https://img.shields.io/pub/v/weibo_kit.svg)](https://pub.dartlang.org/packages/weibo_kit) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/v7lin/fake_weibo/blob/master/LICENSE) flutter版新浪微博SDK @@ -14,6 +14,7 @@ flutter版新浪微博SDK * [flutter版腾讯(QQ)SDK](https://github.com/v7lin/fake_tencent) * [flutter版新浪微博SDK](https://github.com/v7lin/fake_weibo) * [flutter版支付宝SDK](https://github.com/v7lin/fake_alipay) +* [flutter版walle渠道打包工具](https://github.com/v7lin/walle_kit) * [flutter版腾讯(信鸽)推送SDK](https://github.com/v7lin/fake_push) * [flutter版talkingdata移动统计SDK](https://github.com/v7lin/fake_analytics) @@ -35,6 +36,26 @@ flutter版新浪微博SDK # 混淆已打入 Library,随 Library 引用,自动添加到 apk 打包混淆 ``` +#### 获取 android 微信签名信息 + +非官方方法 -> 反编译 app_signatures.apk 所得 + +命令: + +```shell +keytool -list -v -keystore ${your_keystore_path} -storepass ${your_keystore_password} 2>/dev/null | grep -p 'MD5:.*' -o | sed 's/MD5://' | sed 's/ //g' | sed 's/://g' | awk '{print tolower($0)}' +``` + +示例: + +```shell +keytool -list -v -keystore example/android/app/infos/dev.jks -storepass 123456 2>/dev/null | grep -p 'MD5:.*' -o | sed 's/MD5://' | sed 's/ //g' | sed 's/://g' | awk '{print tolower($0)}' +``` + +```shell +28424130a4416d519e00946651d53a46 +``` + ## ios ``` @@ -45,7 +66,7 @@ iOS 9.0 在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id URL Types -weibosdk: identifier=com.weibo schemes=wb${appKey} +weibosdk: identifier=weibo schemes=wb${appKey} ``` ``` @@ -63,6 +84,61 @@ iOS 9系统策略更新,限制了http协议的访问,此外应用需要在 NSExceptionDomains + sina.cn + + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + + weibo.cn + + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + + weibo.com + + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + + sinaimg.cn + + NSIncludesSubdomains + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + + sinajs.cn + + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + sina.com.cn NSIncludesSubdomains @@ -83,7 +159,7 @@ iOS 9系统策略更新,限制了http协议的访问,此外应用需要在 ``` dependencies: - fake_weibo: + weibo_kit: git: url: https://github.com/v7lin/fake_weibo.git ``` @@ -92,7 +168,7 @@ dependencies: ``` dependencies: - fake_weibo: ^${latestTag} + weibo_kit: ^${latestTag} ``` * example @@ -102,10 +178,10 @@ dependencies: ## Getting Started This project is a starting point for a Flutter -[plug-in package](https://flutter.io/developing-packages/), +[plug-in package](https://flutter.dev/developing-packages/), a specialized package that includes platform-specific implementation code for Android and/or iOS. For help getting started with Flutter, view our -[online documentation](https://flutter.io/docs), which offers tutorials, +[online documentation](https://flutter.dev/docs), which offers tutorials, samples, guidance on mobile development, and a full API reference. diff --git a/analysis_options.yaml b/analysis_options.yaml old mode 100644 new mode 100755 index cd9690c..fd29b1d --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,13 +1,27 @@ -# Defines a default set of lint rules enforced for -# projects at Google. For details and rationale, -# see https://github.com/dart-lang/pedantic#enabled-lints. -include: package:pedantic/analysis_options.yaml +# Specify analysis options. +# +# Until there are meta linter rules, each desired lint must be explicitly enabled. +# See: https://github.com/dart-lang/linter/issues/288 +# +# For a list of lints, see: http://dart-lang.github.io/linter/lints/ +# See the configuration guide for more +# https://github.com/dart-lang/sdk/tree/master/pkg/analyzer#configuring-the-analyzer +# +# There are other similar analysis options files in the flutter repos, +# which should be kept in sync with this file: +# +# - analysis_options.yaml (this file) +# - packages/flutter/lib/analysis_options_user.yaml +# - https://github.com/flutter/plugins/blob/master/analysis_options.yaml +# - https://github.com/flutter/engine/blob/master/analysis_options.yaml +# +# This file contains the analysis options used by Flutter tools, such as IntelliJ, +# Android Studio, and the `flutter analyze` command. analyzer: strong-mode: implicit-casts: false - # implicit-dynamic: false - + implicit-dynamic: false errors: # treat missing required parameters as a warning (not a hint) missing_required_param: warning @@ -15,118 +29,175 @@ analyzer: missing_return: warning # allow having TODOs in the code todo: ignore - # Ignore errors like - # 'super_goes_last' is a deprecated lint rule and should not be used • included_file_warning - included_file_warning: ignore - - # 过滤 jaguar_serializer + # Ignore analyzer hints for updating pubspecs when using Future or + # Stream and not importing dart:async + # Please see https://github.com/flutter/flutter/pull/24528 for details. + sdk_version_async_exported_from_core: ignore exclude: - - "**/*.jser.dart" + - "**/*.g.dart" linter: rules: - # these rules are documented on and in the same order as - # the Dart Lint rules page to make maintenance easier - # http://dart-lang.github.io/linter/lints/ - - # === error rules === - - avoid_empty_else - - avoid_slow_async_io - - cancel_subscriptions - # - close_sinks # https://github.com/flutter/flutter/issues/5789 - # - comment_references # blocked on https://github.com/dart-lang/dartdoc/issues/1153 - - control_flow_in_finally - - empty_statements - - hash_and_equals - # - invariant_booleans # https://github.com/flutter/flutter/issues/5790 - - iterable_contains_unrelated_type - - list_remove_unrelated_type - # - literal_only_boolean_expressions # https://github.com/flutter/flutter/issues/5791 - - no_adjacent_strings_in_list - - no_duplicate_case_values - - test_types_in_equals - - throw_in_finally - - unrelated_type_equality_checks - - valid_regexps - - # === style rules === - - always_declare_return_types - # - always_put_control_body_on_new_line - - always_require_non_null_named_parameters - - always_specify_types - - annotate_overrides - # - avoid_annotating_with_dynamic # not yet tested - # - avoid_as # 2019-01-30 removed for no-implicit-casts - # - avoid_catches_without_on_clauses # not yet tested - # - avoid_catching_errors # not yet tested - # - avoid_classes_with_only_static_members # not yet tested - # - avoid_function_literals_in_foreach_calls # not yet tested - - avoid_init_to_null - - avoid_null_checks_in_equality_operators - # - avoid_positional_boolean_parameters # not yet tested - - avoid_return_types_on_setters - # - avoid_returning_null # not yet tested - # - avoid_returning_this # not yet tested - # - avoid_setters_without_getters # not yet tested - # - avoid_types_on_closure_parameters # not yet tested - - await_only_futures - - camel_case_types - # - cascade_invocations # not yet tested - # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 - - directives_ordering - - empty_catches - - empty_constructor_bodies - - implementation_imports - # - join_return_with_assignment # not yet tested - - library_names - - library_prefixes - - non_constant_identifier_names - # - omit_local_variable_types # opposite of always_specify_types - # - one_member_abstracts # too many false positives - # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 - - overridden_fields - - package_api_docs - - package_prefixed_library_names - # - parameter_assignments # we do this commonly - - prefer_adjacent_string_concatenation - - prefer_collection_literals - # - prefer_conditional_assignment # not yet tested - - prefer_const_constructors - # - prefer_constructors_over_static_methods # not yet tested - - prefer_contains - - 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_final_fields # https://github.com/dart-lang/linter/issues/506 - # - prefer_final_locals - # - prefer_foreach # not yet tested - # - prefer_function_declarations_over_variables # not yet tested - - prefer_initializing_formals - # - prefer_interpolation_to_compose_strings # not yet tested - - prefer_is_empty - - prefer_is_not_empty - - prefer_void_to_null - # - recursive_getters # https://github.com/dart-lang/linter/issues/452 - - slash_for_doc_comments - - sort_constructors_first - - sort_unnamed_constructors_first - # - super_goes_last - # - type_annotate_public_apis # subset of always_specify_types - - type_init_formals - # - unawaited_futures # https://github.com/flutter/flutter/issues/5793 - - unnecessary_brace_in_string_interps - - unnecessary_const - - unnecessary_getters_setters - # - unnecessary_lambdas # https://github.com/dart-lang/linter/issues/498 - - unnecessary_new - - unnecessary_null_aware_assignments - - unnecessary_null_in_if_null_operators - # - unnecessary_overrides # https://github.com/dart-lang/linter/issues/626 and https://github.com/dart-lang/linter/issues/627 - - unnecessary_statements - - unnecessary_this - - use_rethrow_when_possible - # - use_setters_to_change_properties # not yet tested - # - use_string_buffers # https://github.com/dart-lang/linter/pull/664 - # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review - - # === pub rules === - - package_names \ No newline at end of file + # these rules are documented on and in the same order as + # the Dart Lint rules page to make maintenance easier + # https://github.com/dart-lang/linter/blob/master/example/all.yaml + - always_declare_return_types + - always_put_control_body_on_new_line + # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 + - always_require_non_null_named_parameters + - always_specify_types + - annotate_overrides + # - avoid_annotating_with_dynamic # conflicts with always_specify_types + # - avoid_as # required for implicit-casts: true + - avoid_bool_literals_in_conditional_expressions + # - avoid_catches_without_on_clauses # we do this commonly + # - avoid_catching_errors # we do this commonly + - avoid_classes_with_only_static_members + # - avoid_double_and_int_checks # only useful when targeting JS runtime + - avoid_empty_else + # - avoid_equals_and_hash_code_on_mutable_classes # not yet tested + - avoid_field_initializers_in_const_classes + - avoid_function_literals_in_foreach_calls + # - avoid_implementing_value_types # not yet tested + - avoid_init_to_null + # - avoid_js_rounded_ints # only useful when targeting JS runtime + - avoid_null_checks_in_equality_operators + # - avoid_positional_boolean_parameters # not yet tested + # - avoid_print # not yet tested + # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) + # - avoid_redundant_argument_values # not yet tested + - avoid_relative_lib_imports + - avoid_renaming_method_parameters + - avoid_return_types_on_setters + # - avoid_returning_null # there are plenty of valid reasons to return null + # - avoid_returning_null_for_future # not yet tested + - avoid_returning_null_for_void + # - avoid_returning_this # there are plenty of valid reasons to return this + # - avoid_setters_without_getters # not yet tested + # - avoid_shadowing_type_parameters # not yet tested + - avoid_single_cascade_in_expression_statements + - avoid_slow_async_io + - avoid_types_as_parameter_names + # - avoid_types_on_closure_parameters # conflicts with always_specify_types + # - avoid_unnecessary_containers # not yet tested + - avoid_unused_constructor_parameters + - avoid_void_async + # - avoid_web_libraries_in_flutter # not yet tested + - await_only_futures + - camel_case_extensions + - camel_case_types + - cancel_subscriptions + # - cascade_invocations # not yet tested + # - close_sinks # not reliable enough + # - 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 + - control_flow_in_finally + # - curly_braces_in_flow_control_structures # not yet tested + # - diagnostic_describe_all_properties # not yet tested + - directives_ordering + - empty_catches + - empty_constructor_bodies + - empty_statements + # - file_names # not yet tested + - flutter_style_todos + - hash_and_equals + - implementation_imports + # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 + - iterable_contains_unrelated_type + # - join_return_with_assignment # not yet tested + - library_names + - library_prefixes + # - lines_longer_than_80_chars # not yet tested + - list_remove_unrelated_type + # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181 + # - missing_whitespace_between_adjacent_strings # not yet tested + - no_adjacent_strings_in_list + - no_duplicate_case_values + # - no_logic_in_create_state # not yet tested + # - no_runtimeType_toString # not yet tested + - non_constant_identifier_names + # - null_closures # not yet tested + # - omit_local_variable_types # opposite of always_specify_types + # - one_member_abstracts # too many false positives + # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 + - overridden_fields + - package_api_docs + - package_names + - package_prefixed_library_names + # - parameter_assignments # we do this commonly + - prefer_adjacent_string_concatenation + - prefer_asserts_in_initializer_lists + # - prefer_asserts_with_message # not yet tested + - prefer_collection_literals + - prefer_conditional_assignment + - prefer_const_constructors + - prefer_const_constructors_in_immutables + - prefer_const_declarations + - prefer_const_literals_to_create_immutables + # - prefer_constructors_over_static_methods # not yet tested + - prefer_contains + # - prefer_double_quotes # opposite of prefer_single_quotes + - 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_final_fields + # - prefer_final_in_for_each + # - prefer_final_locals + - prefer_for_elements_to_map_fromIterable + - prefer_foreach + # - prefer_function_declarations_over_variables # not yet tested + - prefer_generic_function_type_aliases + - prefer_if_elements_to_conditional_expressions + - prefer_if_null_operators + - prefer_initializing_formals + - prefer_inlined_adds + # - prefer_int_literals # not yet tested + # - prefer_interpolation_to_compose_strings # not yet tested + - prefer_is_empty + - prefer_is_not_empty + - prefer_is_not_operator + - prefer_iterable_whereType + # - prefer_mixin # https://github.com/dart-lang/language/issues/32 + # - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932 + # - prefer_relative_imports # not yet tested + - prefer_single_quotes + - prefer_spread_collections + - prefer_typing_uninitialized_variables + - prefer_void_to_null + # - provide_deprecation_message # not yet tested + # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml + - recursive_getters + - slash_for_doc_comments + # - sort_child_properties_last # not yet tested + - sort_constructors_first + - sort_pub_dependencies + - sort_unnamed_constructors_first + - test_types_in_equals + - throw_in_finally + # - type_annotate_public_apis # subset of always_specify_types + - type_init_formals + # - unawaited_futures # too many false positives + # - unnecessary_await_in_return # not yet tested + - unnecessary_brace_in_string_interps + - unnecessary_const + # - unnecessary_final # conflicts with prefer_final_locals + - unnecessary_getters_setters + # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 + - unnecessary_new + - unnecessary_null_aware_assignments + - unnecessary_null_in_if_null_operators + - unnecessary_overrides + - unnecessary_parenthesis + - unnecessary_statements + - unnecessary_string_interpolations + - unnecessary_this + - unrelated_type_equality_checks + # - unsafe_html # not yet tested + - use_full_hex_values_for_flutter_colors + # - use_function_type_syntax_for_parameters # not yet tested + # - use_key_in_widget_constructors # not yet tested + - use_rethrow_when_possible + # - use_setters_to_change_properties # not yet tested + # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 + # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review + - valid_regexps + - void_checks \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 61cb689..8d6db6b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ -group 'io.github.v7lin.fakeweibo' -version '1.0-SNAPSHOT' +group 'io.github.v7lin.weibo_kit' +version '1.0.0' buildscript { repositories { @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.0' } } @@ -19,12 +19,13 @@ rootProject.allprojects { // weibo maven { - url "https://dl.bintray.com/thelasterstar/maven/" + url 'https://dl.bintray.com/thelasterstar/maven/' } } } apply plugin: 'com.android.library' +apply from: './quality.gradle' android { compileSdkVersion 28 @@ -33,9 +34,7 @@ android { minSdkVersion 16 // library 混淆 -> 随 library 引用,自动添加到 apk 打包混淆 - consumerProguardFiles 'consumer-proguard-rules.txt' - - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' } lintOptions { @@ -44,5 +43,7 @@ android { } dependencies { - implementation 'com.sina.weibo.sdk:core:4.3.4:openDefaultRelease@aar' + implementation 'androidx.annotation:annotation:1.0.0' + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'com.sina.weibo.sdk:core:9.12.0:openDefaultRelease@aar' } diff --git a/android/checkstyle.xml b/android/checkstyle.xml new file mode 100644 index 0000000..90627f2 --- /dev/null +++ b/android/checkstyle.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/consumer-proguard-rules.txt b/android/consumer-proguard-rules.txt deleted file mode 100644 index 0b52d31..0000000 --- a/android/consumer-proguard-rules.txt +++ /dev/null @@ -1 +0,0 @@ -# 微博 diff --git a/android/consumer-rules.pro b/android/consumer-rules.pro new file mode 100644 index 0000000..b67468a --- /dev/null +++ b/android/consumer-rules.pro @@ -0,0 +1,4 @@ +# 微博 + +-keep public class com.sina.weibo.sdk.**{*;} +-keep public class com.weibo.ssosdk.**{*;} diff --git a/android/gradle.properties b/android/gradle.properties index 8bd86f6..38c8d45 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..01a286e --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/quality.gradle b/android/quality.gradle new file mode 100644 index 0000000..9b0abf2 --- /dev/null +++ b/android/quality.gradle @@ -0,0 +1,17 @@ +apply plugin: 'checkstyle' + +check.dependsOn 'checkstyle' + +checkstyle { +// toolVersion = "6.15" +} + +task checkstyle(type: Checkstyle) { + configFile project.file('checkstyle.xml') + source 'src/main/java' + ignoreFailures false + showViolations true + include '**/*.java' + + classpath = files() +} diff --git a/android/settings.gradle b/android/settings.gradle index a4ad301..72aa374 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1 +1 @@ -rootProject.name = 'fake_weibo' +rootProject.name = 'weibo_kit' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 9b39cbd..0bdaa19 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,11 +1,6 @@ + package="io.github.v7lin.weibo_kit"> - - - - - diff --git a/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java b/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java deleted file mode 100644 index e2df031..0000000 --- a/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java +++ /dev/null @@ -1,259 +0,0 @@ -package io.github.v7lin.fakeweibo; - -import android.content.Intent; -import android.net.Uri; -import android.text.TextUtils; - -import com.sina.weibo.sdk.WbSdk; -import com.sina.weibo.sdk.api.ImageObject; -import com.sina.weibo.sdk.api.TextObject; -import com.sina.weibo.sdk.api.WebpageObject; -import com.sina.weibo.sdk.api.WeiboMultiMessage; -import com.sina.weibo.sdk.auth.AuthInfo; -import com.sina.weibo.sdk.auth.Oauth2AccessToken; -import com.sina.weibo.sdk.auth.WbAuthListener; -import com.sina.weibo.sdk.auth.WbConnectErrorMessage; -import com.sina.weibo.sdk.auth.sso.SsoHandler; -import com.sina.weibo.sdk.share.WbShareCallback; -import com.sina.weibo.sdk.share.WbShareHandler; -import com.sina.weibo.sdk.utils.Utility; - -import java.util.HashMap; -import java.util.Map; - -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; -import io.flutter.plugin.common.PluginRegistry.Registrar; - -/** - * FakeWeiboPlugin - */ -public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener { - /** - * Plugin registration. - */ - public static void registerWith(Registrar registrar) { - final MethodChannel channel = new MethodChannel(registrar.messenger(), "v7lin.github.io/fake_weibo"); - FakeWeiboPlugin plugin = new FakeWeiboPlugin(registrar, channel); - registrar.addActivityResultListener(plugin); - channel.setMethodCallHandler(plugin); - } - - private static class WeiboErrorCode { - public static final int SUCCESS = 0;//成功 - public static final int USERCANCEL = -1;//用户取消发送 - public static final int SENT_FAIL = -2;//发送失败 - public static final int AUTH_DENY = -3;//授权失败 - public static final int USERCANCEL_INSTALL = -4;//用户取消安装微博客户端 - public static final int PAY_FAIL = -5;//支付失败 - public static final int SHARE_IN_SDK_FAILED = -8;//分享失败 详情见response UserInfo - public static final int UNSUPPORT = -99;//不支持的请求 - public static final int UNKNOWN = -100; - public static final int SSO_PKG_SIGN_ERROR = 21338;//sso package or sign error - } - - private static final String METHOD_REGISTERAPP = "registerApp"; - private static final String METHOD_ISWEIBOINSTALLED = "isWeiboInstalled"; - private static final String METHOD_AUTH = "auth"; - private static final String METHOD_SHARETEXT = "shareText"; - private static final String METHOD_SHAREIMAGE = "shareImage"; - private static final String METHOD_SHAREWEBPAGE = "shareWebpage"; - - private static final String METHOD_ONAUTHRESP = "onAuthResp"; - private static final String METHOD_ONSHAREMSGRESP = "onShareMsgResp"; - - private static final String ARGUMENT_KEY_APPKEY = "appKey"; - private static final String ARGUMENT_KEY_SCOPE = "scope"; - private static final String ARGUMENT_KEY_REDIRECTURL = "redirectUrl"; - private static final String ARGUMENT_KEY_TEXT = "text"; - private static final String ARGUMENT_KEY_TITLE = "title"; - private static final String ARGUMENT_KEY_DESCRIPTION = "description"; - private static final String ARGUMENT_KEY_THUMBDATA = "thumbData"; - private static final String ARGUMENT_KEY_IMAGEDATA = "imageData"; - private static final String ARGUMENT_KEY_IMAGEURI = "imageUri"; - private static final String ARGUMENT_KEY_WEBPAGEURL = "webpageUrl"; - - private static final String ARGUMENT_KEY_RESULT_ERRORCODE = "errorCode"; - private static final String ARGUMENT_KEY_RESULT_ERRORMESSAGE = "errorMessage"; - private static final String ARGUMENT_KEY_RESULT_USERID = "userId"; - private static final String ARGUMENT_KEY_RESULT_ACCESSTOKEN = "accessToken"; - private static final String ARGUMENT_KEY_RESULT_REFRESHTOKEN = "refreshToken"; - private static final String ARGUMENT_KEY_RESULT_EXPIRESIN = "expiresIn"; - - private final Registrar registrar; - private final MethodChannel channel; - - private SsoHandler ssoHandler; - private WbShareHandler shareHandler; - - private FakeWeiboPlugin(Registrar registrar, MethodChannel channel) { - this.registrar = registrar; - this.channel = channel; - } - - @Override - public void onMethodCall(MethodCall call, Result result) { - if (METHOD_REGISTERAPP.equals(call.method)) { - String appKey = call.argument(ARGUMENT_KEY_APPKEY); - String scope = call.argument(ARGUMENT_KEY_SCOPE); - String redirectUrl = call.argument(ARGUMENT_KEY_REDIRECTURL); - - WbSdk.install(registrar.context(), new AuthInfo(registrar.context(), appKey, redirectUrl, scope)); - ssoHandler = new SsoHandler(registrar.activity()); - shareHandler = new WbShareHandler(registrar.activity()); - shareHandler.registerApp(); - result.success(null); - } else if (METHOD_ISWEIBOINSTALLED.equals(call.method)) { - result.success(WbSdk.isWbInstall(registrar.context())); - } else if (METHOD_AUTH.equals(call.method)) { - handleAuthCall(call, result); - } else if (METHOD_SHARETEXT.equals(call.method)) { - handleShareTextCall(call, result); - } else if (METHOD_SHAREIMAGE.equals(call.method) || - METHOD_SHAREWEBPAGE.equals(call.method)) { - handleShareMediaCall(call, result); - } else { - result.notImplemented(); - } - } - - private void handleAuthCall(MethodCall call, Result result) { - if (ssoHandler != null) { - ssoHandler.authorize(new WbAuthListener() { - @Override - public void onSuccess(Oauth2AccessToken oauth2AccessToken) { - Map map = new HashMap<>(); - if (oauth2AccessToken.isSessionValid()) { - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS); - map.put(ARGUMENT_KEY_RESULT_USERID, oauth2AccessToken.getUid()); - map.put(ARGUMENT_KEY_RESULT_ACCESSTOKEN, oauth2AccessToken.getToken()); - map.put(ARGUMENT_KEY_RESULT_REFRESHTOKEN, oauth2AccessToken.getRefreshToken()); - long expiresIn = (long) Math.ceil((oauth2AccessToken.getExpiresTime() - System.currentTimeMillis()) / 1000.0); - map.put(ARGUMENT_KEY_RESULT_EXPIRESIN, expiresIn);// 向上取整 - } else { - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN); - } - channel.invokeMethod(METHOD_ONAUTHRESP, map); - } - - @Override - public void cancel() { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL); - channel.invokeMethod(METHOD_ONAUTHRESP, map); - } - - @Override - public void onFailure(WbConnectErrorMessage wbConnectErrorMessage) { - // 微博有毒,WbConnectErrorMessage对象两个属性设置错误 - if (TextUtils.equals(wbConnectErrorMessage.getErrorMessage(), "21338")) { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SSO_PKG_SIGN_ERROR); - map.put(ARGUMENT_KEY_RESULT_ERRORMESSAGE, wbConnectErrorMessage.getErrorCode()); - channel.invokeMethod(METHOD_ONAUTHRESP, map); - } else { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN); - channel.invokeMethod(METHOD_ONAUTHRESP, map); - } - } - }); - } - result.success(null); - } - - private void handleShareTextCall(MethodCall call, Result result) { - if (shareHandler != null) { - WeiboMultiMessage message = new WeiboMultiMessage(); - - TextObject object = new TextObject(); - object.text = call.argument(ARGUMENT_KEY_TEXT);// 1024 - - message.textObject = object; - - shareHandler.shareMessage(message, false); - } - result.success(null); - } - - private void handleShareMediaCall(MethodCall call, Result result) { - if (shareHandler != null) { - WeiboMultiMessage message = new WeiboMultiMessage(); - - if (METHOD_SHAREIMAGE.equals(call.method)) { - if (call.hasArgument(ARGUMENT_KEY_TEXT)) { - TextObject object = new TextObject(); - object.text = call.argument(ARGUMENT_KEY_TEXT);// 1024 - - message.textObject = object; - } - - ImageObject object = new ImageObject(); - if (call.hasArgument(ARGUMENT_KEY_IMAGEDATA)) { - object.imageData = call.argument(ARGUMENT_KEY_IMAGEDATA);// 2 * 1024 * 1024 - } else if (call.hasArgument(ARGUMENT_KEY_IMAGEURI)) { - String imageUri = call.argument(ARGUMENT_KEY_IMAGEURI); - object.imagePath = Uri.parse(imageUri).getPath();// 512 - 10 * 1024 * 1024 - } - - message.mediaObject = object; - } else if (METHOD_SHAREWEBPAGE.equals(call.method)) { - WebpageObject object = new WebpageObject(); - object.identify = Utility.generateGUID(); - object.title = call.argument(ARGUMENT_KEY_TITLE);// 512 - object.description = call.argument(ARGUMENT_KEY_DESCRIPTION);// 1024 - object.thumbData = call.argument(ARGUMENT_KEY_THUMBDATA);// 32 * 1024 - object.defaultText = call.argument(ARGUMENT_KEY_DESCRIPTION); - object.actionUrl = call.argument(ARGUMENT_KEY_WEBPAGEURL);// 512 - - message.mediaObject = object; - } - - shareHandler.shareMessage(message, false); - } - result.success(null); - } - - // --- ActivityResultListener - - @Override - public boolean onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == 32973) { - if (ssoHandler != null) { - ssoHandler.authorizeCallBack(requestCode, resultCode, data); - } - return true; - } - if (requestCode == WbShareHandler.WB_SHARE_REQUEST) { - if (shareHandler != null) { - shareHandler.doResultIntent(data, new WbShareCallback() { - @Override - public void onWbShareSuccess() { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS); - channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); - } - - @Override - public void onWbShareCancel() { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL); - channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); - } - - @Override - public void onWbShareFail() { - Map map = new HashMap<>(); - map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SHARE_IN_SDK_FAILED); - channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); - } - }); - } - return true; - } - return false; - } -} diff --git a/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKit.java b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKit.java new file mode 100644 index 0000000..cf0bda1 --- /dev/null +++ b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKit.java @@ -0,0 +1,274 @@ +package io.github.v7lin.weibo_kit; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.sina.weibo.sdk.api.ImageObject; +import com.sina.weibo.sdk.api.TextObject; +import com.sina.weibo.sdk.api.WebpageObject; +import com.sina.weibo.sdk.api.WeiboMultiMessage; +import com.sina.weibo.sdk.auth.AuthInfo; +import com.sina.weibo.sdk.auth.Oauth2AccessToken; +import com.sina.weibo.sdk.auth.WbAuthListener; +import com.sina.weibo.sdk.common.UiError; +import com.sina.weibo.sdk.openapi.IWBAPI; +import com.sina.weibo.sdk.openapi.WBAPIFactory; +import com.sina.weibo.sdk.share.WbShareCallback; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MethodCall; +import io.flutter.plugin.common.MethodChannel; +import io.flutter.plugin.common.PluginRegistry; + +public class WeiboKit implements MethodChannel.MethodCallHandler, PluginRegistry.ActivityResultListener { + + private static class WeiboErrorCode { + public static final int SUCCESS = 0;//成功 + public static final int USERCANCEL = -1;//用户取消发送 + public static final int SENT_FAIL = -2;//发送失败 + public static final int AUTH_DENY = -3;//授权失败 + public static final int USERCANCEL_INSTALL = -4;//用户取消安装微博客户端 + public static final int PAY_FAIL = -5;//支付失败 + public static final int SHARE_IN_SDK_FAILED = -8;//分享失败 详情见response UserInfo + public static final int UNSUPPORT = -99;//不支持的请求 + public static final int UNKNOWN = -100; + } + + private static final String METHOD_REGISTERAPP = "registerApp"; + private static final String METHOD_ISINSTALLED = "isInstalled"; + private static final String METHOD_AUTH = "auth"; + private static final String METHOD_SHARETEXT = "shareText"; + private static final String METHOD_SHAREIMAGE = "shareImage"; + private static final String METHOD_SHAREWEBPAGE = "shareWebpage"; + + private static final String METHOD_ONAUTHRESP = "onAuthResp"; + private static final String METHOD_ONSHAREMSGRESP = "onShareMsgResp"; + + private static final String ARGUMENT_KEY_APPKEY = "appKey"; + private static final String ARGUMENT_KEY_SCOPE = "scope"; + private static final String ARGUMENT_KEY_REDIRECTURL = "redirectUrl"; + private static final String ARGUMENT_KEY_TEXT = "text"; + private static final String ARGUMENT_KEY_TITLE = "title"; + private static final String ARGUMENT_KEY_DESCRIPTION = "description"; + private static final String ARGUMENT_KEY_THUMBDATA = "thumbData"; + private static final String ARGUMENT_KEY_IMAGEDATA = "imageData"; + private static final String ARGUMENT_KEY_IMAGEURI = "imageUri"; + private static final String ARGUMENT_KEY_WEBPAGEURL = "webpageUrl"; + + private static final String ARGUMENT_KEY_RESULT_ERRORCODE = "errorCode"; + private static final String ARGUMENT_KEY_RESULT_ERRORMESSAGE = "errorMessage"; + private static final String ARGUMENT_KEY_RESULT_USERID = "userId"; + private static final String ARGUMENT_KEY_RESULT_ACCESSTOKEN = "accessToken"; + private static final String ARGUMENT_KEY_RESULT_REFRESHTOKEN = "refreshToken"; + private static final String ARGUMENT_KEY_RESULT_EXPIRESIN = "expiresIn"; + + // + + private Context applicationContext; + private Activity activity; + + private MethodChannel channel; + + private IWBAPI iwbapi; + + public WeiboKit() { + super(); + } + + public WeiboKit(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/weibo_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)) { + String appKey = call.argument(ARGUMENT_KEY_APPKEY); + String scope = call.argument(ARGUMENT_KEY_SCOPE); + String redirectUrl = call.argument(ARGUMENT_KEY_REDIRECTURL); + + iwbapi = WBAPIFactory.createWBAPI(activity); + iwbapi.registerApp(applicationContext, new AuthInfo(applicationContext, appKey, redirectUrl, scope)); + result.success(null); + } else if (METHOD_ISINSTALLED.equals(call.method)) { + result.success(iwbapi.isWBAppInstalled()); + } else if (METHOD_AUTH.equals(call.method)) { + handleAuthCall(call, result); + } else if (METHOD_SHARETEXT.equals(call.method)) { + handleShareTextCall(call, result); + } else if (METHOD_SHAREIMAGE.equals(call.method) || + METHOD_SHAREWEBPAGE.equals(call.method)) { + handleShareMediaCall(call, result); + } else { + result.notImplemented(); + } + } + + private void handleAuthCall(MethodCall call, MethodChannel.Result result) { + if (iwbapi != null) { + iwbapi.authorize(new WbAuthListener() { + @Override + public void onComplete(Oauth2AccessToken token) { + Map map = new HashMap<>(); + if (token.isSessionValid()) { + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS); + map.put(ARGUMENT_KEY_RESULT_USERID, token.getUid()); + map.put(ARGUMENT_KEY_RESULT_ACCESSTOKEN, token.getAccessToken()); + map.put(ARGUMENT_KEY_RESULT_REFRESHTOKEN, token.getRefreshToken()); + long expiresIn = (long) Math.ceil((token.getExpiresTime() - System.currentTimeMillis()) / 1000.0); + map.put(ARGUMENT_KEY_RESULT_EXPIRESIN, expiresIn);// 向上取整 + } else { + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN); + } + if (channel != null) { + channel.invokeMethod(METHOD_ONAUTHRESP, map); + } + } + + @Override + public void onError(UiError uiError) { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN); + channel.invokeMethod(METHOD_ONAUTHRESP, map); + } + + @Override + public void onCancel() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL); + if (channel != null) { + channel.invokeMethod(METHOD_ONAUTHRESP, map); + } + } + }); + } + result.success(null); + } + + private void handleShareTextCall(MethodCall call, MethodChannel.Result result) { + WeiboMultiMessage message = new WeiboMultiMessage(); + + TextObject object = new TextObject(); + object.text = call.argument(ARGUMENT_KEY_TEXT);// 1024 + + message.textObject = object; + + if (iwbapi != null) { + iwbapi.shareMessage(message, false); + } + result.success(null); + } + + private void handleShareMediaCall(MethodCall call, MethodChannel.Result result) { + WeiboMultiMessage message = new WeiboMultiMessage(); + + if (METHOD_SHAREIMAGE.equals(call.method)) { + if (call.hasArgument(ARGUMENT_KEY_TEXT)) { + TextObject object = new TextObject(); + object.text = call.argument(ARGUMENT_KEY_TEXT);// 1024 + + message.textObject = object; + } + + ImageObject object = new ImageObject(); + if (call.hasArgument(ARGUMENT_KEY_IMAGEDATA)) { + object.imageData = call.argument(ARGUMENT_KEY_IMAGEDATA);// 2 * 1024 * 1024 + } else if (call.hasArgument(ARGUMENT_KEY_IMAGEURI)) { + String imageUri = call.argument(ARGUMENT_KEY_IMAGEURI); + object.imagePath = Uri.parse(imageUri).getPath();// 512 - 10 * 1024 * 1024 + } + + message.mediaObject = object; + } else if (METHOD_SHAREWEBPAGE.equals(call.method)) { + WebpageObject object = new WebpageObject(); + object.identify = UUID.randomUUID().toString(); + object.title = call.argument(ARGUMENT_KEY_TITLE);// 512 + object.description = call.argument(ARGUMENT_KEY_DESCRIPTION);// 1024 + object.thumbData = call.argument(ARGUMENT_KEY_THUMBDATA);// 32 * 1024 + object.defaultText = call.argument(ARGUMENT_KEY_DESCRIPTION); + object.actionUrl = call.argument(ARGUMENT_KEY_WEBPAGEURL);// 512 + + message.mediaObject = object; + } + + if (iwbapi != null) { + iwbapi.shareMessage(message, false); + } + result.success(null); + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case 32973: + if (iwbapi != null) { + iwbapi.authorizeCallback(requestCode, resultCode, data); + } + return true; + case 10001: + if (iwbapi != null) { + iwbapi.doResultIntent(data, new WbShareCallback() { + @Override + public void onComplete() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS); + if (channel != null) { + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + } + + @Override + public void onError(UiError uiError) { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SHARE_IN_SDK_FAILED); + if (channel != null) { + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + } + + @Override + public void onCancel() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL); + if (channel != null) { + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + } + }); + } + return true; + } + return false; + } +} diff --git a/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java new file mode 100644 index 0000000..e8d3df1 --- /dev/null +++ b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java @@ -0,0 +1,76 @@ +package io.github.v7lin.weibo_kit; + +import androidx.annotation.NonNull; + +import io.flutter.embedding.engine.plugins.FlutterPlugin; +import io.flutter.embedding.engine.plugins.activity.ActivityAware; +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; +import io.flutter.plugin.common.PluginRegistry.Registrar; + +/** WeiboKitPlugin */ +public class WeiboKitPlugin implements FlutterPlugin, ActivityAware { + // 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 + // plugin registration via this function while apps migrate to use the new Android APIs + // post-flutter-1.12 via https://flutter.dev/go/android-project-migration. + // + // 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(Registrar registrar) { + WeiboKit weiboKit = new WeiboKit(registrar.context(), registrar.activity()); + registrar.addActivityResultListener(weiboKit); + weiboKit.startListening(registrar.messenger()); + } + + // --- FlutterPlugin + + private final WeiboKit weiboKit; + + private ActivityPluginBinding pluginBinding; + + public WeiboKitPlugin() { + weiboKit = new WeiboKit(); + } + + @Override + public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { + weiboKit.setApplicationContext(binding.getApplicationContext()); + weiboKit.setActivity(null); + weiboKit.startListening(binding.getBinaryMessenger()); + } + + @Override + public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { + weiboKit.setApplicationContext(null); + weiboKit.setActivity(null); + weiboKit.stopListening(); + } + + // --- ActivityAware + + @Override + public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { + weiboKit.setActivity(binding.getActivity()); + pluginBinding = binding; + pluginBinding.addActivityResultListener(weiboKit); + } + + @Override + public void onDetachedFromActivityForConfigChanges() { + onDetachedFromActivity(); + } + + @Override + public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { + onAttachedToActivity(binding); + } + + @Override + public void onDetachedFromActivity() { + weiboKit.setActivity(null); + pluginBinding.removeActivityResultListener(weiboKit); + pluginBinding = null; + } +} diff --git a/example/.gitignore b/example/.gitignore index 47e0b4d..1ba9c33 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,6 +1,5 @@ # Miscellaneous *.class -*.lock *.log *.pyc *.swp @@ -16,56 +15,29 @@ *.iws .idea/ -# Visual Studio Code related -.vscode/ +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ # Flutter/Dart/Pub related **/doc/api/ .dart_tool/ .flutter-plugins +.flutter-plugins-dependencies .packages .pub-cache/ .pub/ -build/ +/build/ -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java +# Web related +lib/generated_plugin_registrant.dart -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json # Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/example/.metadata b/example/.metadata index 460bc20..7c361dd 100644 --- a/example/.metadata +++ b/example/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b + revision: b041144f833e05cf463b8887fa12efdec9493488 channel: stable project_type: app diff --git a/example/README.md b/example/README.md index 6765301..4b650e0 100644 --- a/example/README.md +++ b/example/README.md @@ -1,6 +1,6 @@ -# fake_weibo_example +# weibo_kit_example -Demonstrates how to use the fake_weibo plugin. +Demonstrates how to use the weibo_kit plugin. ## Getting Started @@ -8,9 +8,9 @@ This project is a starting point for a Flutter application. A few resources to get you started if this is your first Flutter project: -- [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook) +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) -For help getting started with Flutter, view our -[online documentation](https://flutter.io/docs), which offers tutorials, +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, samples, guidance on mobile development, and a full API reference. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml old mode 100644 new mode 100755 index 9fa477b..81dd0eb --- a/example/analysis_options.yaml +++ b/example/analysis_options.yaml @@ -1,32 +1,4 @@ -# Defines a default set of lint rules enforced for -# projects at Google. For details and rationale, -# see https://github.com/dart-lang/pedantic#enabled-lints. -include: package:pedantic/analysis_options.yaml +# Take our settings from the repo's main analysis_options.yaml file, but include +# an additional rule to validate that public members are documented. -analyzer: - strong-mode: - implicit-casts: false - # implicit-dynamic: false - -linter: - rules: - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - test_types_in_equals - - unrelated_type_equality_checks - - valid_regexps - - annotate_overrides - - hash_and_equals - - prefer_is_not_empty - - avoid_empty_else - - cancel_subscriptions - - close_sinks - - always_declare_return_types - - camel_case_types - - empty_constructor_bodies - - avoid_init_to_null - # - constant_identifier_names - - one_member_abstracts - - slash_for_doc_comments - - sort_constructors_first - - unnecessary_new \ No newline at end of file +include: ../analysis_options.yaml diff --git a/example/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 840b71c..e600dea 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -33,12 +33,11 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "io.github.v7lin.fakeweiboexample" + applicationId "io.github.v7lin.weibo_kit_example" minSdkVersion 16 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { @@ -46,11 +45,6 @@ android { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig signingConfigs.debug - - minifyEnabled true - useProguard true - - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } @@ -58,9 +52,3 @@ android { flutter { source '../..' } - -dependencies { - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -} diff --git a/example/android/app/proguard-rules.pro b/example/android/app/proguard-rules.pro deleted file mode 100644 index a52c689..0000000 --- a/example/android/app/proguard-rules.pro +++ /dev/null @@ -1,8 +0,0 @@ -#Flutter Wrapper --keep class io.flutter.app.** { *; } --keep class io.flutter.plugin.** { *; } --keep class io.flutter.util.** { *; } --keep class io.flutter.view.** { *; } --keep class io.flutter.** { *; } --keep class io.flutter.plugins.** { *; } --dontwarn io.flutter.** \ No newline at end of file diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..2799474 --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 31f890e..20d319c 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,12 +1,5 @@ - - - - + package="io.github.v7lin.weibo_kit_example"> - + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" + /> + + + + diff --git a/example/android/app/src/main/java/io/github/v7lin/fakeweiboexample/MainActivity.java b/example/android/app/src/main/java/io/github/v7lin/fakeweiboexample/MainActivity.java deleted file mode 100644 index 9cd00a4..0000000 --- a/example/android/app/src/main/java/io/github/v7lin/fakeweiboexample/MainActivity.java +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.v7lin.fakeweiboexample; - -import android.os.Bundle; -import io.flutter.app.FlutterActivity; -import io.flutter.plugins.GeneratedPluginRegistrant; - -public class MainActivity extends FlutterActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - GeneratedPluginRegistrant.registerWith(this); - } -} diff --git a/example/android/app/src/main/java/io/github/v7lin/weibo_kit_example/MainActivity.java b/example/android/app/src/main/java/io/github/v7lin/weibo_kit_example/MainActivity.java new file mode 100644 index 0000000..443ad2d --- /dev/null +++ b/example/android/app/src/main/java/io/github/v7lin/weibo_kit_example/MainActivity.java @@ -0,0 +1,6 @@ +package io.github.v7lin.weibo_kit_example; + +import io.flutter.embedding.android.FlutterActivity; + +public class MainActivity extends FlutterActivity { +} diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml index 00fa441..1f83a33 100644 --- a/example/android/app/src/main/res/values/styles.xml +++ b/example/android/app/src/main/res/values/styles.xml @@ -1,8 +1,18 @@ + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..2799474 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle index bb8a303..e0d7ae2 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.0' } } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 8bd86f6..38c8d45 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 2819f02..296b146 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..d3b6a40 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,15 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + include ':app' -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() +def localPropertiesFile = new File(rootProject.projectDir, "local.properties") +def properties = new Properties() -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } -} +assert localPropertiesFile.exists() +localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory -} +def flutterSdkPath = properties.getProperty("flutter.sdk") +assert flutterSdkPath != null, "flutter.sdk not set in local.properties" +apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" diff --git a/example/images/icon/2.0x/ic_launcher.png b/example/images/icon/2.0x/ic_launcher.png deleted file mode 100644 index 09d4391482be68e9e4a07fab769b5de337d16eb1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 721 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ diff --git a/example/images/icon/2.0x/timg.jpeg b/example/images/icon/2.0x/timg.jpeg deleted file mode 100644 index 5c2debd25f5f5e21836d71acbcd4f12f3cfa206c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105374 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

r9 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�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𝔊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�__G|zJAaVGR&2T*a` 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 CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable App CFBundleIdentifier diff --git a/example/ios/Podfile b/example/ios/Podfile index d077b08..5a69b89 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -15,49 +15,64 @@ def parse_KV_file(file, separator='=') if !File.exists? file_abs_path return []; end - pods_ary = [] + generated_key_values = {} skip_line_start_symbols = ["#", "/"] - File.foreach(file_abs_path) { |line| - next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } - plugin = line.split(pattern=separator) - if plugin.length == 2 - podname = plugin[0].strip() - path = plugin[1].strip() - podpath = File.expand_path("#{path}", file_abs_path) - pods_ary.push({:name => podname, :path => podpath}); - else - puts "Invalid plugin specification: #{line}" - end - } - return pods_ary + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values end target 'Runner' do + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock # referring to absolute paths on developers' machines. system('rm -rf .symlinks') system('mkdir -p .symlinks/plugins') - - # Flutter Pods - generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') - if generated_xcode_build_settings.empty? - puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first." - end - generated_xcode_build_settings.map { |p| - if p[:name] == 'FLUTTER_FRAMEWORK_DIR' - symlink = File.join('.symlinks', 'flutter') - File.symlink(File.dirname(p[:path]), symlink) - pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) - end - } - - # Plugin Pods plugin_pods = parse_KV_file('../.flutter-plugins') - plugin_pods.map { |p| - symlink = File.join('.symlinks', 'plugins', p[:name]) - File.symlink(p[:path], symlink) - pod p[:name], :path => File.join(symlink, 'ios') - } + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end end post_install do |installer| diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..18a25fd --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,50 @@ +PODS: + - Flutter (1.0.0) + - path_provider (0.0.1): + - Flutter + - path_provider_linux (0.0.1): + - Flutter + - path_provider_macos (0.0.1): + - Flutter + - weibo_kit (1.0.0): + - Flutter + - weibo_kit/vendor (= 1.0.0) + - weibo_kit/vendor (1.0.0): + - Flutter + - Weibo_SDK (~> 3.2.7) + - Weibo_SDK (3.2.7) + +DEPENDENCIES: + - Flutter (from `Flutter`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) + - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) + - weibo_kit (from `.symlinks/plugins/weibo_kit/ios`) + +SPEC REPOS: + trunk: + - Weibo_SDK + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + path_provider_linux: + :path: ".symlinks/plugins/path_provider_linux/ios" + path_provider_macos: + :path: ".symlinks/plugins/path_provider_macos/ios" + weibo_kit: + :path: ".symlinks/plugins/weibo_kit/ios" + +SPEC CHECKSUMS: + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 + path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 + weibo_kit: b3178a26e9ea391bf9fec5c6ef1ee3f5d38735ad + Weibo_SDK: 5a4d08f7e1fedbb635435e4585c8c0439c7da089 + +PODFILE CHECKSUM: f32fb4e7c14f8b3ca19a369d7be425dd9241af27 + +COCOAPODS: 1.8.4 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 3b6809e..17a88d4 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,23 +3,18 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 51; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; + 3CDD46DAA37A5371B2A70EC2 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FF490F57C9D1EABC131B9426 /* libPods-Runner.a */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - F607D74C02A3D09C94D22138 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CC78EBE1496BEBD8B37D6CBF /* libPods-Runner.a */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -29,8 +24,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, - 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -40,24 +33,22 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3329B2A78B4C4B969972BA19 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; - 40991B03E162E46C56B9D900 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 8C3451CC4D3C94BCDF014D4C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 983F5802E11ABE4DB378B222 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; - CC78EBE1496BEBD8B37D6CBF /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + C5C37EFD234544E62872E54A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + E0BD40F9BEC5B3B35E91E09D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + FF490F57C9D1EABC131B9426 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,31 +56,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, - 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, - F607D74C02A3D09C94D22138 /* libPods-Runner.a in Frameworks */, + 3CDD46DAA37A5371B2A70EC2 /* libPods-Runner.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 118CEF9B5D8D03B56D5D7C1F /* Pods */ = { + 6C41AA3581FC291CB33F9055 /* Pods */ = { isa = PBXGroup; children = ( - 3329B2A78B4C4B969972BA19 /* Pods-Runner.debug.xcconfig */, - 983F5802E11ABE4DB378B222 /* Pods-Runner.release.xcconfig */, - 40991B03E162E46C56B9D900 /* Pods-Runner.profile.xcconfig */, + E0BD40F9BEC5B3B35E91E09D /* Pods-Runner.debug.xcconfig */, + C5C37EFD234544E62872E54A /* Pods-Runner.release.xcconfig */, + 8C3451CC4D3C94BCDF014D4C /* Pods-Runner.profile.xcconfig */, ); - name = Pods; + path = Pods; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( - 3B80C3931E831B6300D905FE /* App.framework */, 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEBA1CF902C7004384FC /* Flutter.framework */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, @@ -103,8 +90,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - 118CEF9B5D8D03B56D5D7C1F /* Pods */, - BC7D72E583FD7697E09D7784 /* Frameworks */, + 6C41AA3581FC291CB33F9055 /* Pods */, + 97EA60ED8F200E6F573A9890 /* Frameworks */, ); sourceTree = ""; }; @@ -140,10 +127,10 @@ name = "Supporting Files"; sourceTree = ""; }; - BC7D72E583FD7697E09D7784 /* Frameworks */ = { + 97EA60ED8F200E6F573A9890 /* Frameworks */ = { isa = PBXGroup; children = ( - CC78EBE1496BEBD8B37D6CBF /* libPods-Runner.a */, + FF490F57C9D1EABC131B9426 /* libPods-Runner.a */, ); name = Frameworks; sourceTree = ""; @@ -155,15 +142,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 5E40D85FABB1650818BB4959 /* [CP] Check Pods Manifest.lock */, + 631D2F29201BBC63DC66AD43 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - BA5C6C2059F783B8F3A1D718 /* [CP] Embed Pods Frameworks */, - 2E75A410B195E117A49D1E82 /* [CP] Copy Pods Resources */, + 1F77EE1FF4C528197971DB94 /* [CP] Embed Pods Frameworks */, + BEFF80007E7E4E2B2694658C /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -180,21 +167,19 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0910; - ORGANIZATIONNAME = "The Chromium Authors"; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; - DevelopmentTeam = 78W43A3TE2; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); @@ -215,7 +200,6 @@ files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); @@ -224,22 +208,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 2E75A410B195E117A49D1E82 /* [CP] Copy Pods Resources */ = { + 1F77EE1FF4C528197971DB94 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_ROOT}/Weibo_SDK/libWeiboSDK/WeiboSDK.bundle", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Copy Pods Resources"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle", + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { @@ -254,18 +237,22 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 5E40D85FABB1650818BB4959 /* [CP] Check Pods Manifest.lock */ = { + 631D2F29201BBC63DC66AD43 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); + inputFileListPaths = ( + ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); @@ -288,22 +275,21 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - BA5C6C2059F783B8F3A1D718 /* [CP] Embed Pods Frameworks */ = { + BEFF80007E7E4E2B2694658C /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -355,12 +341,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -384,6 +372,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -395,7 +384,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -403,12 +391,15 @@ ); INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.weiboKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -428,12 +419,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -482,12 +475,14 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -511,6 +506,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -522,7 +518,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -530,12 +525,15 @@ ); INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.weiboKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -547,7 +545,6 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 78W43A3TE2; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -555,12 +552,15 @@ ); INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 9.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); - PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.weiboKitExample; PRODUCT_NAME = "$(TARGET_NAME)"; VERSIONING_SYSTEM = "apple-generic"; }; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 786d6aa..a28140c 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ @@ -46,7 +45,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m index 59a72e9..70e8393 100644 --- a/example/ios/Runner/AppDelegate.m +++ b/example/ios/Runner/AppDelegate.m @@ -1,5 +1,5 @@ -#include "AppDelegate.h" -#include "GeneratedPluginRegistrant.h" +#import "AppDelegate.h" +#import "GeneratedPluginRegistrant.h" @implementation AppDelegate diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index 3d43d11e66f4de3da27ed045ca4fe38ad8b48094..dc9ada4725e9b0ddb1deab583e5b5102493aa332 100644 GIT binary patch literal 10932 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 P-1+_A+?hGkL;m(J7kc&K diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index b4c975c..9203935 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -3,7 +3,7 @@ CFBundleDevelopmentRegion - en + $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - fake_weibo_example + weibo_kit_example CFBundlePackageType APPL CFBundleShortVersionString @@ -24,10 +24,13 @@ CFBundleTypeRole Editor CFBundleURLName - com.weibo + weibo CFBundleURLSchemes - wb3393861383 + your + weibo + app + key @@ -48,6 +51,17 @@ NSExceptionDomains + sina.cn + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + sina.com.cn NSExceptionMinimumTLSVersion @@ -59,6 +73,50 @@ NSThirdPartyExceptionRequiresForwardSecrecy + sinaimg.cn + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + + sinajs.cn + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + + weibo.cn + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + + weibo.com + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + UILaunchStoryboardName diff --git a/example/lib/main.dart b/example/lib/main.dart index 357d622..98fc2c4 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,9 +1,14 @@ import 'dart:async'; import 'dart:io'; +import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:fake_weibo/fake_weibo.dart'; +import 'package:image/image.dart' as image; +import 'package:okhttp_kit/okhttp_kit.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart' as path_provider; +import 'package:weibo_kit/weibo_kit.dart'; void main() { runZoned(() { @@ -37,7 +42,7 @@ class Home extends StatefulWidget { } class _HomeState extends State { - static const String _WEIBO_APP_KEY = '3393861383'; + static const String _WEIBO_APP_KEY = 'your weibo app key'; static const List _WEIBO_SCOPE = [ WeiboScope.ALL, ]; @@ -86,14 +91,14 @@ class _HomeState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Fake Weibo Demo'), + title: const Text('Weibo Kit Demo'), ), body: ListView( children: [ ListTile( title: const Text('环境检查'), onTap: () async { - String content = 'weibo: ${await _weibo.isWeiboInstalled()}'; + String content = 'weibo: ${await _weibo.isInstalled()}'; _showTips('环境检查', content); }, ), @@ -138,30 +143,70 @@ class _HomeState extends State { ListTile( title: const Text('图片分享'), onTap: () async { - AssetImage image = const AssetImage('images/icon/timg.jpeg'); - AssetBundleImageKey key = - await image.obtainKey(createLocalImageConfiguration(context)); - ByteData imageData = await key.bundle.load(key.name); - await _weibo.shareImage( - text: 'Share Text', - imageData: imageData.buffer.asUint8List(), - ); + OkHttpClient client = OkHttpClientBuilder().build(); + Response resp = await client + .newCall(RequestBuilder() + .get() + .url(HttpUrl.parse( + 'https://www.baidu.com/img/bd_logo1.png?where=super')) + .build()) + .enqueue(); + if (resp.isSuccessful()) { + Directory saveDir = Platform.isAndroid + ? await path_provider.getExternalStorageDirectory() + : await path_provider.getApplicationDocumentsDirectory(); + 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 _weibo.shareImage( + text: 'Share Text', + imageUri: Uri.file(saveFile.path), + ); + } }, ), ListTile( title: const Text('网页分享'), onTap: () async { - AssetImage image = - const AssetImage('images/icon/ic_launcher.png'); - AssetBundleImageKey key = - await image.obtainKey(createLocalImageConfiguration(context)); - ByteData thumbData = await key.bundle.load(key.name); - await _weibo.shareWebpage( - title: 'title', - description: 'share webpage', - thumbData: thumbData.buffer.asUint8List(), - webpageUrl: 'https://www.baidu.com', - ); + OkHttpClient client = OkHttpClientBuilder().build(); + Response resp = await client + .newCall(RequestBuilder() + .get() + .url(HttpUrl.parse( + 'https://www.baidu.com/img/bd_logo1.png?where=super')) + .build()) + .enqueue(); + if (resp.isSuccessful()) { + Directory saveDir = Platform.isAndroid + ? await path_provider.getExternalStorageDirectory() + : await path_provider.getApplicationDocumentsDirectory(); + File saveFile = File(path.join(saveDir.path, 'timg.png')); + if (!saveFile.existsSync()) { + saveFile.createSync(recursive: true); + saveFile.writeAsBytesSync( + await resp.body().bytes(), + flush: true, + ); + } + image.Image thumbnail = + image.decodePng(saveFile.readAsBytesSync()); + Uint8List thumbData = thumbnail.getBytes(); + if (thumbData.length > 32 * 1024) { + thumbData = Uint8List.fromList(image.encodeJpg(thumbnail, + quality: 100 * 32 * 1024 ~/ thumbData.length)); + } + await _weibo.shareWebpage( + title: 'title', + description: 'share webpage', + thumbData: thumbData.buffer.asUint8List(), + webpageUrl: 'https://www.baidu.com', + ); + } }, ), ], @@ -170,7 +215,7 @@ class _HomeState extends State { } void _showTips(String title, String content) { - showDialog( + showDialog( context: context, builder: (BuildContext context) { return AlertDialog( diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..35c4572 --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,287 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.0" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.10.11" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.12" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + okhttp_kit: + dependency: "direct main" + description: + name: okhttp_kit + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + path: + dependency: "direct main" + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + path_provider: + dependency: "direct main" + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+1" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4+3" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.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.2" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.13" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.15" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + weibo_kit: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "1.0.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.1" +sdks: + dart: ">=2.7.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 6080fa2..7679513 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,29 +1,40 @@ -name: fake_weibo_example -description: Demonstrates how to use the fake_weibo plugin. -publish_to: 'none' +name: weibo_kit_example +description: Demonstrates how to use the weibo_kit plugin. +version: 1.0.0+1000 +# The following line prevents the package from being accidentally published to +# 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 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" dependencies: flutter: sdk: flutter + weibo_kit: + # When depending on this package from a real application you should use: + # weibo_kit: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^0.1.2 + cupertino_icons: ^0.1.3 - fake_weibo: - path: ../ + path: ^1.6.4 + path_provider: ^1.4.0 + + okhttp_kit: ^1.0.0 dev_dependencies: flutter_test: sdk: flutter - pedantic: '>=1.4.0 <3.0.0' - # For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec +# following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: @@ -34,15 +45,15 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - assets: - - images/icon/timg.jpeg - - images/icon/ic_launcher.png + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. + # https://flutter.dev/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see - # https://flutter.io/assets-and-images/#from-packages + # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a @@ -62,4 +73,4 @@ flutter: # weight: 700 # # For details regarding fonts from package dependencies, - # see https://flutter.io/custom-fonts/#from-packages + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/ios/.gitignore b/ios/.gitignore index 710ec6c..aa479fd 100644 --- a/ios/.gitignore +++ b/ios/.gitignore @@ -34,3 +34,4 @@ Icon? .tags* /Flutter/Generated.xcconfig +/Flutter/flutter_export_environment.sh \ No newline at end of file diff --git a/ios/Classes/FakeWeiboPlugin.h b/ios/Classes/FakeWeiboPlugin.h deleted file mode 100644 index 0391846..0000000 --- a/ios/Classes/FakeWeiboPlugin.h +++ /dev/null @@ -1,4 +0,0 @@ -#import - -@interface FakeWeiboPlugin : NSObject -@end diff --git a/ios/Classes/WeiboKitPlugin.h b/ios/Classes/WeiboKitPlugin.h new file mode 100644 index 0000000..23c4b02 --- /dev/null +++ b/ios/Classes/WeiboKitPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface WeiboKitPlugin : NSObject +@end diff --git a/ios/Classes/FakeWeiboPlugin.m b/ios/Classes/WeiboKitPlugin.m similarity index 80% rename from ios/Classes/FakeWeiboPlugin.m rename to ios/Classes/WeiboKitPlugin.m index 550e7e5..8843dbf 100644 --- a/ios/Classes/FakeWeiboPlugin.m +++ b/ios/Classes/WeiboKitPlugin.m @@ -1,25 +1,25 @@ -#import "FakeWeiboPlugin.h" +#import "WeiboKitPlugin.h" #import -@interface FakeWeiboPlugin () +@interface WeiboKitPlugin () @end -@implementation FakeWeiboPlugin { +@implementation WeiboKitPlugin { FlutterMethodChannel * _channel; } -+ (void)registerWithRegistrar:(NSObject*)registrar { - FlutterMethodChannel* channel = [FlutterMethodChannel - methodChannelWithName:@"v7lin.github.io/fake_weibo" - binaryMessenger:[registrar messenger]]; - FakeWeiboPlugin* instance = [[FakeWeiboPlugin alloc] initWithChannel:channel]; - [registrar addApplicationDelegate:instance]; - [registrar addMethodCallDelegate:instance channel:channel]; ++ (void)registerWithRegistrar:(NSObject *)registrar { + FlutterMethodChannel *channel = + [FlutterMethodChannel methodChannelWithName:@"v7lin.github.io/weibo_kit" + binaryMessenger:[registrar messenger]]; + WeiboKitPlugin *instance = [[WeiboKitPlugin alloc] initWithChannel:channel]; + [registrar addApplicationDelegate:instance]; + [registrar addMethodCallDelegate:instance channel:channel]; } static NSString * const METHOD_REGISTERAPP = @"registerApp"; -static NSString * const METHOD_ISWEIBOINSTALLED = @"isWeiboInstalled"; +static NSString * const METHOD_ISINSTALLED = @"isInstalled"; static NSString * const METHOD_AUTH = @"auth"; static NSString * const METHOD_SHARETEXT = @"shareText"; static NSString * const METHOD_SHAREIMAGE = @"shareImage"; @@ -54,23 +54,24 @@ static NSString * const ARGUMENT_KEY_RESULT_EXPIRESIN = @"expiresIn"; return self; } -- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { - if ([METHOD_REGISTERAPP isEqualToString:call.method]) { - NSString * appKey = call.arguments[ARGUMENT_KEY_APPKEY]; - [WeiboSDK registerApp:appKey]; - result(nil); - } else if ([METHOD_ISWEIBOINSTALLED isEqualToString:call.method]) { - result([NSNumber numberWithBool:[WeiboSDK isWeiboAppInstalled]]); - } else if ([METHOD_AUTH isEqualToString:call.method]) { - [self handleAuthCall:call result:result]; - } else if ([METHOD_SHARETEXT isEqualToString:call.method]) { - [self handleShareTextCall:call result:result]; - } else if ([METHOD_SHAREIMAGE isEqualToString:call.method] || - [METHOD_SHAREWEBPAGE isEqualToString:call.method]) { - [self handleShareMediaCall:call result:result]; - } else { - result(FlutterMethodNotImplemented); - } +- (void)handleMethodCall:(FlutterMethodCall *)call + result:(FlutterResult)result { + if ([METHOD_REGISTERAPP isEqualToString:call.method]) { + NSString * appKey = call.arguments[ARGUMENT_KEY_APPKEY]; + [WeiboSDK registerApp:appKey]; + result(nil); + } else if ([METHOD_ISINSTALLED isEqualToString:call.method]) { + result([NSNumber numberWithBool:[WeiboSDK isWeiboAppInstalled]]); + } else if ([METHOD_AUTH isEqualToString:call.method]) { + [self handleAuthCall:call result:result]; + } else if ([METHOD_SHARETEXT isEqualToString:call.method]) { + [self handleShareTextCall:call result:result]; + } else if ([METHOD_SHAREIMAGE isEqualToString:call.method] || + [METHOD_SHAREWEBPAGE isEqualToString:call.method]) { + [self handleShareMediaCall:call result:result]; + } else { + result(FlutterMethodNotImplemented); + } } -(void)handleAuthCall:(FlutterMethodCall*)call result:(FlutterResult)result { diff --git a/ios/fake_weibo.podspec b/ios/fake_weibo.podspec deleted file mode 100644 index fdf6d61..0000000 --- a/ios/fake_weibo.podspec +++ /dev/null @@ -1,24 +0,0 @@ -# -# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html -# -Pod::Spec.new do |s| - s.name = 'fake_weibo' - s.version = '0.0.1' - s.summary = 'A new Flutter plugin.' - s.description = <<-DESC -A new Flutter plugin. - DESC - s.homepage = 'http://example.com' - s.license = { :file => '../LICENSE' } - s.author = { 'Your Company' => 'email@example.com' } - s.source = { :path => '.' } - s.source_files = 'Classes/**/*' - s.public_header_files = 'Classes/**/*.h' - s.dependency 'Flutter' - # 微博 - s.static_framework = true - s.dependency 'Weibo_SDK', '~> 3.2.5.1' - - s.ios.deployment_target = '9.0' -end - diff --git a/ios/weibo_kit.podspec b/ios/weibo_kit.podspec new file mode 100644 index 0000000..cbeb767 --- /dev/null +++ b/ios/weibo_kit.podspec @@ -0,0 +1,28 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint weibo_kit.podspec' to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'weibo_kit' + s.version = '1.0.0' + s.summary = 'A powerful weibo plugin for Flutter.' + s.description = <<-DESC +A powerful weibo plugin for Flutter. + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.public_header_files = 'Classes/**/*.h' + s.dependency 'Flutter' + s.platform = :ios, '9.0' + + s.static_framework = true + s.subspec 'vendor' do |sp| + sp.dependency 'Weibo_SDK', '~> 3.2.7' + end + + # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported. + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' } +end diff --git a/lib/fake_weibo.dart b/lib/fake_weibo.dart deleted file mode 100644 index 11879a6..0000000 --- a/lib/fake_weibo.dart +++ /dev/null @@ -1,9 +0,0 @@ -library fake_weibo; - -export 'src/domain/api/weibo_api_resp.dart'; -export 'src/domain/api/weibo_user_info_resp.dart' - hide WeiboUserInfoRespSerializer; -export 'src/domain/sdk/weibo_auth_resp.dart' hide WeiboAuthRespSerializer; -export 'src/domain/sdk/weibo_sdk_resp.dart' hide WeiboSdkRespSerializer; -export 'src/weibo.dart'; -export 'src/weibo_scope.dart'; diff --git a/lib/src/domain/api/weibo_user_info_resp.jser.dart b/lib/src/domain/api/weibo_user_info_resp.jser.dart deleted file mode 100644 index caf32d7..0000000 --- a/lib/src/domain/api/weibo_user_info_resp.jser.dart +++ /dev/null @@ -1,54 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'weibo_user_info_resp.dart'; - -// ************************************************************************** -// JaguarSerializerGenerator -// ************************************************************************** - -abstract class _$WeiboUserInfoRespSerializer - implements Serializer { - @override - Map toMap(WeiboUserInfoResp model) { - if (model == null) return null; - Map ret = {}; - setMapValue(ret, 'id', model.id); - setMapValue(ret, 'idstr', model.idstr); - setMapValue(ret, 'screen_name', model.screenName); - setMapValue(ret, 'name', model.name); - setMapValue(ret, 'location', model.location); - setMapValue(ret, 'description', model.description); - setMapValue(ret, 'profile_image_url', model.profileImageUrl); - setMapValue(ret, 'gender', model.gender); - setMapValue(ret, 'avatar_large', model.avatarLarge); - setMapValue(ret, 'avatar_hd', model.avatarHd); - setMapValue(ret, 'error_code', model.errorCode); - setMapValue(ret, 'error', model.error); - setMapValue(ret, 'request', model.request); - return ret; - } - - @override - WeiboUserInfoResp fromMap(Map map) { - if (map == null) return null; - final obj = new WeiboUserInfoResp( - errorCode: map['error_code'] as int ?? getJserDefault('errorCode'), - error: map['error'] as String ?? getJserDefault('error'), - request: map['request'] as String ?? getJserDefault('request'), - id: map['id'] as int ?? getJserDefault('id'), - idstr: map['idstr'] as String ?? getJserDefault('idstr'), - screenName: - map['screen_name'] as String ?? getJserDefault('screenName'), - name: map['name'] as String ?? getJserDefault('name'), - location: map['location'] as String ?? getJserDefault('location'), - description: - map['description'] as String ?? getJserDefault('description'), - profileImageUrl: map['profile_image_url'] as String ?? - getJserDefault('profileImageUrl'), - gender: map['gender'] as String ?? getJserDefault('gender'), - avatarLarge: - map['avatar_large'] as String ?? getJserDefault('avatarLarge'), - avatarHd: map['avatar_hd'] as String ?? getJserDefault('avatarHd')); - return obj; - } -} diff --git a/lib/src/domain/sdk/weibo_auth_resp.dart b/lib/src/domain/sdk/weibo_auth_resp.dart deleted file mode 100644 index 8724dd8..0000000 --- a/lib/src/domain/sdk/weibo_auth_resp.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:jaguar_serializer/jaguar_serializer.dart'; -import 'package:fake_weibo/src/domain/sdk/weibo_sdk_resp.dart'; - -part 'weibo_auth_resp.jser.dart'; - -@GenSerializer() -class WeiboAuthRespSerializer extends Serializer - with _$WeiboAuthRespSerializer {} - -class WeiboAuthResp extends WeiboSdkResp { - WeiboAuthResp({ - int errorCode, - String errorMessage, - this.userId, - this.accessToken, - this.refreshToken, - this.expiresIn, - }) : super(errorCode: errorCode, errorMessage: errorMessage); - - final String userId; - final String accessToken; - final String refreshToken; - final int expiresIn; -} diff --git a/lib/src/domain/sdk/weibo_auth_resp.jser.dart b/lib/src/domain/sdk/weibo_auth_resp.jser.dart deleted file mode 100644 index ab16ef5..0000000 --- a/lib/src/domain/sdk/weibo_auth_resp.jser.dart +++ /dev/null @@ -1,38 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'weibo_auth_resp.dart'; - -// ************************************************************************** -// JaguarSerializerGenerator -// ************************************************************************** - -abstract class _$WeiboAuthRespSerializer implements Serializer { - @override - Map toMap(WeiboAuthResp model) { - if (model == null) return null; - Map ret = {}; - setMapValue(ret, 'userId', model.userId); - setMapValue(ret, 'accessToken', model.accessToken); - setMapValue(ret, 'refreshToken', model.refreshToken); - setMapValue(ret, 'expiresIn', model.expiresIn); - setMapValue(ret, 'errorCode', model.errorCode); - setMapValue(ret, 'errorMessage', model.errorMessage); - return ret; - } - - @override - WeiboAuthResp fromMap(Map map) { - if (map == null) return null; - final obj = new WeiboAuthResp( - errorCode: map['errorCode'] as int ?? getJserDefault('errorCode'), - errorMessage: - map['errorMessage'] as String ?? getJserDefault('errorMessage'), - userId: map['userId'] as String ?? getJserDefault('userId'), - accessToken: - map['accessToken'] as String ?? getJserDefault('accessToken'), - refreshToken: - map['refreshToken'] as String ?? getJserDefault('refreshToken'), - expiresIn: map['expiresIn'] as int ?? getJserDefault('expiresIn')); - return obj; - } -} diff --git a/lib/src/domain/sdk/weibo_sdk_resp.jser.dart b/lib/src/domain/sdk/weibo_sdk_resp.jser.dart deleted file mode 100644 index 2196011..0000000 --- a/lib/src/domain/sdk/weibo_sdk_resp.jser.dart +++ /dev/null @@ -1,28 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'weibo_sdk_resp.dart'; - -// ************************************************************************** -// JaguarSerializerGenerator -// ************************************************************************** - -abstract class _$WeiboSdkRespSerializer implements Serializer { - @override - Map toMap(WeiboSdkResp model) { - if (model == null) return null; - Map ret = {}; - setMapValue(ret, 'errorCode', model.errorCode); - setMapValue(ret, 'errorMessage', model.errorMessage); - return ret; - } - - @override - WeiboSdkResp fromMap(Map map) { - if (map == null) return null; - final obj = new WeiboSdkResp( - errorCode: map['errorCode'] as int ?? getJserDefault('errorCode'), - errorMessage: - map['errorMessage'] as String ?? getJserDefault('errorMessage')); - return obj; - } -} diff --git a/lib/src/domain/api/weibo_api_resp.dart b/lib/src/model/api/weibo_api_resp.dart similarity index 100% rename from lib/src/domain/api/weibo_api_resp.dart rename to lib/src/model/api/weibo_api_resp.dart diff --git a/lib/src/domain/api/weibo_user_info_resp.dart b/lib/src/model/api/weibo_user_info_resp.dart similarity index 70% rename from lib/src/domain/api/weibo_user_info_resp.dart rename to lib/src/model/api/weibo_user_info_resp.dart index 8b84b25..7379538 100644 --- a/lib/src/domain/api/weibo_user_info_resp.dart +++ b/lib/src/model/api/weibo_user_info_resp.dart @@ -1,12 +1,13 @@ -import 'package:jaguar_serializer/jaguar_serializer.dart'; -import 'package:fake_weibo/src/domain/api/weibo_api_resp.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:weibo_kit/src/model/api/weibo_api_resp.dart'; -part 'weibo_user_info_resp.jser.dart'; - -@GenSerializer(nameFormatter: toSnakeCase) -class WeiboUserInfoRespSerializer extends Serializer - with _$WeiboUserInfoRespSerializer {} +part 'weibo_user_info_resp.g.dart'; +@JsonSerializable( + anyMap: true, + explicitToJson: true, + fieldRename: FieldRename.snake, +) class WeiboUserInfoResp extends WeiboApiResp { WeiboUserInfoResp({ int errorCode, @@ -24,6 +25,9 @@ class WeiboUserInfoResp extends WeiboApiResp { this.avatarHd, }) : super(errorCode: errorCode, error: error, request: request); + factory WeiboUserInfoResp.fromJson(Map json) => + _$WeiboUserInfoRespFromJson(json); + /// 用户UID(int64) final int id; @@ -61,4 +65,6 @@ class WeiboUserInfoResp extends WeiboApiResp { bool isFemale() { return gender == 'f'; } + + Map toJson() => _$WeiboUserInfoRespToJson(this); } diff --git a/lib/src/model/api/weibo_user_info_resp.g.dart b/lib/src/model/api/weibo_user_info_resp.g.dart new file mode 100644 index 0000000..34995c2 --- /dev/null +++ b/lib/src/model/api/weibo_user_info_resp.g.dart @@ -0,0 +1,42 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_user_info_resp.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +WeiboUserInfoResp _$WeiboUserInfoRespFromJson(Map json) { + return WeiboUserInfoResp( + errorCode: json['error_code'] as int, + error: json['error'] as String, + request: json['request'] as String, + id: json['id'] as int, + idstr: json['idstr'] as String, + screenName: json['screen_name'] as String, + name: json['name'] as String, + location: json['location'] as String, + description: json['description'] as String, + profileImageUrl: json['profile_image_url'] as String, + gender: json['gender'] as String, + avatarLarge: json['avatar_large'] as String, + avatarHd: json['avatar_hd'] as String, + ); +} + +Map _$WeiboUserInfoRespToJson(WeiboUserInfoResp instance) => + { + 'error_code': instance.errorCode, + 'error': instance.error, + 'request': instance.request, + 'id': instance.id, + 'idstr': instance.idstr, + 'screen_name': instance.screenName, + 'name': instance.name, + 'location': instance.location, + 'description': instance.description, + 'profile_image_url': instance.profileImageUrl, + 'gender': instance.gender, + 'avatar_large': instance.avatarLarge, + 'avatar_hd': instance.avatarHd, + }; diff --git a/lib/src/model/sdk/weibo_auth_resp.dart b/lib/src/model/sdk/weibo_auth_resp.dart new file mode 100644 index 0000000..e4cfb87 --- /dev/null +++ b/lib/src/model/sdk/weibo_auth_resp.dart @@ -0,0 +1,30 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:weibo_kit/src/model/sdk/weibo_sdk_resp.dart'; + +part 'weibo_auth_resp.g.dart'; + +@JsonSerializable( + anyMap: true, + explicitToJson: true, +) +class WeiboAuthResp extends WeiboSdkResp { + WeiboAuthResp({ + int errorCode, + String errorMessage, + this.userId, + this.accessToken, + this.refreshToken, + this.expiresIn, + }) : super(errorCode: errorCode, errorMessage: errorMessage); + + factory WeiboAuthResp.fromJson(Map json) => + _$WeiboAuthRespFromJson(json); + + final String userId; + final String accessToken; + final String refreshToken; + final int expiresIn; + + @override + Map toJson() => _$WeiboAuthRespToJson(this); +} diff --git a/lib/src/model/sdk/weibo_auth_resp.g.dart b/lib/src/model/sdk/weibo_auth_resp.g.dart new file mode 100644 index 0000000..d224e25 --- /dev/null +++ b/lib/src/model/sdk/weibo_auth_resp.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_auth_resp.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +WeiboAuthResp _$WeiboAuthRespFromJson(Map json) { + return WeiboAuthResp( + errorCode: json['errorCode'] as int, + errorMessage: json['errorMessage'] as String, + userId: json['userId'] as String, + accessToken: json['accessToken'] as String, + refreshToken: json['refreshToken'] as String, + expiresIn: json['expiresIn'] as int, + ); +} + +Map _$WeiboAuthRespToJson(WeiboAuthResp instance) => + { + 'errorCode': instance.errorCode, + 'errorMessage': instance.errorMessage, + 'userId': instance.userId, + 'accessToken': instance.accessToken, + 'refreshToken': instance.refreshToken, + 'expiresIn': instance.expiresIn, + }; diff --git a/lib/src/domain/sdk/weibo_sdk_resp.dart b/lib/src/model/sdk/weibo_sdk_resp.dart similarity index 70% rename from lib/src/domain/sdk/weibo_sdk_resp.dart rename to lib/src/model/sdk/weibo_sdk_resp.dart index 9528b9e..30c6c27 100644 --- a/lib/src/domain/sdk/weibo_sdk_resp.dart +++ b/lib/src/model/sdk/weibo_sdk_resp.dart @@ -1,17 +1,20 @@ -import 'package:jaguar_serializer/jaguar_serializer.dart'; +import 'package:json_annotation/json_annotation.dart'; -part 'weibo_sdk_resp.jser.dart'; - -@GenSerializer() -class WeiboSdkRespSerializer extends Serializer - with _$WeiboSdkRespSerializer {} +part 'weibo_sdk_resp.g.dart'; +@JsonSerializable( + anyMap: true, + explicitToJson: true, +) class WeiboSdkResp { WeiboSdkResp({ int errorCode, this.errorMessage, }) : errorCode = errorCode ?? SUCCESS; + factory WeiboSdkResp.fromJson(Map json) => + _$WeiboSdkRespFromJson(json); + /// 成功 static const int SUCCESS = 0; @@ -39,9 +42,8 @@ class WeiboSdkResp { /// 未知 static const int UNKNOWN = -100; - /// sso package or sign error - static const int SSO_PKG_SIGN_ERROR = 21338; - final int errorCode; final String errorMessage; + + Map toJson() => _$WeiboSdkRespToJson(this); } diff --git a/lib/src/model/sdk/weibo_sdk_resp.g.dart b/lib/src/model/sdk/weibo_sdk_resp.g.dart new file mode 100644 index 0000000..2745ee0 --- /dev/null +++ b/lib/src/model/sdk/weibo_sdk_resp.g.dart @@ -0,0 +1,20 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_sdk_resp.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +WeiboSdkResp _$WeiboSdkRespFromJson(Map json) { + return WeiboSdkResp( + errorCode: json['errorCode'] as int, + errorMessage: json['errorMessage'] as String, + ); +} + +Map _$WeiboSdkRespToJson(WeiboSdkResp instance) => + { + 'errorCode': instance.errorCode, + 'errorMessage': instance.errorMessage, + }; diff --git a/lib/src/weibo.dart b/lib/src/weibo.dart index 6544df0..9c0f684 100644 --- a/lib/src/weibo.dart +++ b/lib/src/weibo.dart @@ -3,11 +3,11 @@ import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; -import 'package:fake_weibo/src/domain/api/weibo_user_info_resp.dart'; -import 'package:fake_weibo/src/domain/sdk/weibo_auth_resp.dart'; -import 'package:fake_weibo/src/domain/sdk/weibo_sdk_resp.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:meta/meta.dart'; +import 'package:weibo_kit/src/model/api/weibo_user_info_resp.dart'; +import 'package:weibo_kit/src/model/sdk/weibo_auth_resp.dart'; +import 'package:weibo_kit/src/model/sdk/weibo_sdk_resp.dart'; class Weibo { Weibo() { @@ -15,7 +15,7 @@ class Weibo { } static const String _METHOD_REGISTERAPP = 'registerApp'; - static const String _METHOD_ISWEIBOINSTALLED = 'isWeiboInstalled'; + static const String _METHOD_ISINSTALLED = 'isInstalled'; static const String _METHOD_AUTH = 'auth'; static const String _METHOD_SHARETEXT = 'shareText'; static const String _METHOD_SHAREIMAGE = 'shareImage'; @@ -41,7 +41,7 @@ class Weibo { 'https://api.weibo.com/oauth2/default.html'; final MethodChannel _channel = - const MethodChannel('v7lin.github.io/fake_weibo'); + const MethodChannel('v7lin.github.io/weibo_kit'); final StreamController _authRespStreamController = StreamController.broadcast(); @@ -57,7 +57,7 @@ class Weibo { }) { assert(appKey != null && appKey.isNotEmpty); assert(scope != null && scope.isNotEmpty); - return _channel.invokeMethod( + return _channel.invokeMethod( _METHOD_REGISTERAPP, { _ARGUMENT_KEY_APPKEY: appKey, @@ -70,12 +70,12 @@ class Weibo { Future _handleMethod(MethodCall call) async { switch (call.method) { case _METHOD_ONAUTHRESP: - _authRespStreamController.add(WeiboAuthRespSerializer() - .fromMap(call.arguments as Map)); + _authRespStreamController.add( + WeiboAuthResp.fromJson(call.arguments as Map)); break; case _METHOD_ONSHAREMSGRESP: - _shareMsgRespStreamController.add(WeiboSdkRespSerializer() - .fromMap(call.arguments as Map)); + _shareMsgRespStreamController.add( + WeiboSdkResp.fromJson(call.arguments as Map)); break; } } @@ -90,8 +90,8 @@ class Weibo { return _shareMsgRespStreamController.stream; } - Future isWeiboInstalled() async { - return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool; + Future isInstalled() { + return _channel.invokeMethod(_METHOD_ISINSTALLED); } /// 登录 @@ -102,7 +102,7 @@ class Weibo { }) { assert(appKey != null && appKey.isNotEmpty); assert(scope != null && scope.isNotEmpty); - return _channel.invokeMethod( + return _channel.invokeMethod( _METHOD_AUTH, { _ARGUMENT_KEY_APPKEY: appKey, @@ -131,8 +131,8 @@ class Weibo { }).then((HttpClientResponse response) async { if (response.statusCode == HttpStatus.ok) { String content = await utf8.decodeStream(response); - return WeiboUserInfoRespSerializer() - .fromMap(json.decode(content) as Map); + return WeiboUserInfoResp.fromJson( + json.decode(content) as Map); } throw HttpException( 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); @@ -145,15 +145,15 @@ class Weibo { String accessToken, Map params, ) { - params.putIfAbsent('source', () => appkey); - params.putIfAbsent('access_token', () => accessToken); + params['source'] = appkey; + params['access_token'] = accessToken; Uri baseUri = Uri.parse(baseUrl); Map> queryParametersAll = Map>.of(baseUri.queryParametersAll); - params.forEach((String key, String value) { - queryParametersAll.remove(key); - queryParametersAll.putIfAbsent(key, () => [value]); - }); + for (MapEntry entry in params.entries) { + queryParametersAll.remove(entry.key); + queryParametersAll.putIfAbsent(entry.key, () => [entry.value]); + } return baseUri.replace(queryParameters: queryParametersAll); } @@ -162,7 +162,7 @@ class Weibo { @required String text, }) { assert(text != null && text.length <= 1024); - return _channel.invokeMethod( + return _channel.invokeMethod( _METHOD_SHARETEXT, { _ARGUMENT_KEY_TEXT: text, @@ -182,17 +182,14 @@ class Weibo { imageUri.isScheme(_SCHEME_FILE) && imageUri.toFilePath().length <= 512 && File.fromUri(imageUri).lengthSync() <= 10 * 1024 * 1024)); - Map map = {}; - if (text != null && text.isNotEmpty) { - map.putIfAbsent(_ARGUMENT_KEY_TEXT, () => text); - } - if (imageData != null) { - map.putIfAbsent(_ARGUMENT_KEY_IMAGEDATA, () => imageData); - } - if (imageUri != null) { - map.putIfAbsent(_ARGUMENT_KEY_IMAGEURI, () => imageUri.toString()); - } - return _channel.invokeMethod(_METHOD_SHAREIMAGE, map); + return _channel.invokeMethod( + _METHOD_SHAREIMAGE, + { + if (text != null && text.isNotEmpty) _ARGUMENT_KEY_TEXT: text, + if (imageData != null) _ARGUMENT_KEY_IMAGEDATA: imageData, + if (imageUri != null) _ARGUMENT_KEY_IMAGEURI: imageUri.toString(), + }, + ); } /// 分享 - 网页 @@ -210,7 +207,7 @@ class Weibo { assert(webpageUrl != null && webpageUrl.isNotEmpty && webpageUrl.length <= 255); - return _channel.invokeMethod( + return _channel.invokeMethod( _METHOD_SHAREWEBPAGE, { _ARGUMENT_KEY_TITLE: title, diff --git a/lib/src/weibo_scope.dart b/lib/src/weibo_constant.dart similarity index 100% rename from lib/src/weibo_scope.dart rename to lib/src/weibo_constant.dart diff --git a/lib/weibo_kit.dart b/lib/weibo_kit.dart new file mode 100644 index 0000000..832c008 --- /dev/null +++ b/lib/weibo_kit.dart @@ -0,0 +1,8 @@ +library weibo_kit; + +export 'src/model/api/weibo_api_resp.dart'; +export 'src/model/api/weibo_user_info_resp.dart'; +export 'src/model/sdk/weibo_auth_resp.dart'; +export 'src/model/sdk/weibo_sdk_resp.dart'; +export 'src/weibo.dart'; +export 'src/weibo_constant.dart'; diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..5db9c3d --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,546 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.39.10" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.0" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.0" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.2" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.9" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.10.0" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.0" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.3.2" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.flutter-io.cn" + source: hosted + version: "7.1.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.3.0" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.6" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.0" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.10.11" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.14.0+3" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.4" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.12" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + io: + dependency: transitive + description: + name: io + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.4" + js: + dependency: transitive + description: + name: js + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.2" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.1" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.3.0" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.11.4" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.6+3" + node_interop: + dependency: transitive + description: + name: node_interop + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + node_io: + dependency: transitive + description: + name: node_io + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.1" + okhttp_kit: + dependency: "direct dev" + description: + name: okhttp_kit + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + path: + dependency: "direct dev" + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + path_provider: + dependency: "direct dev" + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+1" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4+3" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pedantic: + dependency: "direct dev" + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.0" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.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.2" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.13" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.5" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.7.5" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.3" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.5" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.15" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.1+2" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.7+15" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.1" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.1" +sdks: + dart: ">=2.7.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 3bcac81..bb610e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,52 +1,60 @@ -name: fake_weibo +name: weibo_kit description: A powerful weibo plugin for Flutter. -version: 0.2.4 -author: v7lin +version: 1.0.0 +# author: v7lin homepage: https://github.com/v7lin/fake_weibo environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.7.0 <3.0.0" + flutter: ">=1.10.0" dependencies: flutter: sdk: flutter - meta: ^1.1.6 - - jaguar_serializer: ^2.2.12 + json_annotation: '>=2.0.0 <4.0.0' dev_dependencies: flutter_test: sdk: flutter - pedantic: '>=1.4.0 <3.0.0' + path: ^1.6.4 + path_provider: ^1.4.0 + + okhttp_kit: ^1.0.0 + + pedantic: build_runner: - jaguar_serializer_cli: + json_serializable: # For information on the generic Dart part of this file, see the -# following page: https://www.dartlang.org/tools/pub/pubspec +# following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: # This section identifies this Flutter project as a plugin project. - # The androidPackage and pluginClass identifiers should not ordinarily + # The 'pluginClass' and Android 'package' identifiers should not ordinarily # be modified. They are used by the tooling to maintain consistency when # adding or updating assets for this project. plugin: - androidPackage: io.github.v7lin.fakeweibo - pluginClass: FakeWeiboPlugin + platforms: + android: + package: io.github.v7lin.weibo_kit + pluginClass: WeiboKitPlugin + ios: + pluginClass: WeiboKitPlugin # To add assets to your plugin package, add an assets section, like this: # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg # # For details regarding assets in packages, see - # https://flutter.io/assets-and-images/#from-packages + # https://flutter.dev/assets-and-images/#from-packages # # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.io/assets-and-images/#resolution-aware. + # https://flutter.dev/assets-and-images/#resolution-aware. # To add custom fonts to your plugin package, add a fonts section here, # in this "flutter" section. Each entry in this list should have a @@ -66,4 +74,4 @@ flutter: # weight: 700 # # For details regarding fonts in packages, see - # https://flutter.io/custom-fonts/#from-packages + # https://flutter.dev/custom-fonts/#from-packages diff --git a/test/fake_weibo_test.dart b/test/fake_weibo_test.dart deleted file mode 100644 index ab73b3a..0000000 --- a/test/fake_weibo_test.dart +++ /dev/null @@ -1 +0,0 @@ -void main() {} diff --git a/test/jaguar_test.dart b/test/jaguar_test.dart deleted file mode 100644 index ab3063c..0000000 --- a/test/jaguar_test.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'dart:convert'; - -import 'package:fake_weibo/src/domain/api/weibo_user_info_resp.dart'; -import 'package:fake_weibo/src/domain/sdk/weibo_auth_resp.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:jaguar_serializer/jaguar_serializer.dart'; - -void main() { - test('smoke test - snake case', () { - print('${toSnakeCase('oneField')}'); - print('${toSnakeCase('oneField_street')}'); - print('${toSnakeCase('one_field')}'); - }); - - test('smoke test - kebab case', () { - print('${toKebabCase('oneField')}'); - print('${toKebabCase('oneField_street')}'); - print('${toKebabCase('one_field')}'); - }); - - test('smoke test - camel case', () { - print('${toCamelCase('oneField')}'); - print('${toCamelCase('oneField_street')}'); - print('${toCamelCase('one_field')}'); - }); - - test('smoke test - jaguar_serializer', () { - WeiboAuthResp authResp = WeiboAuthRespSerializer().fromMap(json.decode( - '{"expiresIn":157679999,"errorCode":0,"accessToken":"2.00s67kHGj4SghD8e46233eea9O1IDB","userId":"5611295980","refreshToken":"2.00s67kHGj4SghD6ee52b48200iqHz3"}') - as Map); - expect(authResp.errorCode, equals(0)); - expect(authResp.expiresIn, equals(157679999)); - expect(authResp.accessToken, equals('2.00s67kHGj4SghD8e46233eea9O1IDB')); - - WeiboUserInfoResp userInfoResp = WeiboUserInfoRespSerializer().fromMap( - json.decode( - '{"id":5611295980,"idstr":"5611295980","class":1,"screen_name":"v7lin","name":"v7lin","province":"35","city":"1","location":"福建 福州","description":"","url":"","profile_image_url":"http://tvax4.sinaimg.cn/crop.0.0.640.640.50/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","cover_image_phone":"http://ww1.sinaimg.cn/crop.0.0.640.640.640/549d0121tw1egm1kjly3jj20hs0hsq4f.jpg","profile_url":"u/5611295980","domain":"","weihao":"","gender":"m","followers_count":1,"friends_count":1,"pagefriends_count":0,"statuses_count":0,"video_status_count":0,"favourites_count":0,"created_at":"Mon May 18 19:32:52 +0800 2015","following":false,"allow_all_act_msg":false,"geo_enabled":true,"verified":false,"verified_type":-1,"remark":"","insecurity":{"sexual_content":false},"ptype":0,"allow_all_comment":true,"avatar_large":"http://tvax4.sinaimg.cn/crop.0.0.640.640.180/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","avatar_hd":"http://tvax4.sinaimg.cn/crop.0.0.640.640.1024/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","verified_reason":"","verified_trade":"","verified_reason_url":"","verified_source":"","verified_source_url":"","follow_me":false,"like":false,"like_me":false,"online_status":0,"bi_followers_count":0,"lang":"zh-cn","star":0,"mbtype":0,"mbrank":0,"block_word":0,"block_app":0,"credit_score":80,"user_ability":0,"urank":4,"story_read_state":-1,"vclub_member":0,"is_teenager":0,"is_guardian":0,"is_teenager_list":0}') - as Map); - expect(userInfoResp.errorCode, equals(0)); - expect(userInfoResp.id, equals(5611295980)); - expect(userInfoResp.screenName, equals('v7lin')); - expect( - userInfoResp.avatarHd, - equals( - 'http://tvax4.sinaimg.cn/crop.0.0.640.640.1024/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg')); - }); -} diff --git a/test/weibo_kit_test.dart b/test/weibo_kit_test.dart new file mode 100644 index 0000000..b992a95 --- /dev/null +++ b/test/weibo_kit_test.dart @@ -0,0 +1,79 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pedantic/pedantic.dart'; +import 'package:weibo_kit/weibo_kit.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + const MethodChannel channel = MethodChannel('v7lin.github.io/weibo_kit'); + final Weibo weibo = Weibo(); + + setUp(() { + channel.setMockMethodCallHandler((MethodCall call) async { + switch (call.method) { + case 'registerApp': + return null; + case 'isInstalled': + return true; + case 'auth': + unawaited(channel.binaryMessenger.handlePlatformMessage( + channel.name, + channel.codec.encodeMethodCall( + MethodCall('onAuthResp', json.decode('{"errorCode":-1}'))), + (ByteData data) { + // mock success + }, + )); + return null; + case 'shareText': + case 'shareImage': + case 'shareWebpage': + unawaited(channel.binaryMessenger.handlePlatformMessage( + channel.name, + channel.codec.encodeMethodCall( + MethodCall('onShareMsgResp', json.decode('{"errorCode":-1}'))), + (ByteData data) { + // mock success + }, + )); + return null; + } + throw PlatformException(code: '0', message: '想啥呢,升级插件不想升级Mock?'); + }); + }); + + tearDown(() { + channel.setMockMethodCallHandler(null); + }); + + test('isInstalled', () async { + expect(await weibo.isInstalled(), true); + }); + + test('auth', () async { + StreamSubscription sub = + weibo.authResp().listen((WeiboAuthResp resp) { + expect(resp.errorCode, WeiboSdkResp.USERCANCEL); + }); + await weibo.auth( + appKey: 'your weibo app key', + scope: [WeiboScope.ALL], + ); + await sub.cancel(); + }); + + test('share', () async { + StreamSubscription sub = + weibo.shareMsgResp().listen((WeiboSdkResp resp) { + expect(resp.errorCode, WeiboSdkResp.USERCANCEL); + }); + await weibo.shareText( + text: 'share text', + ); + await sub.cancel(); + }); +}