commit 733366e948372739d777bc9194769082ebeaf696 Author: v7lin Date: Tue Mar 5 12:18:08 2019 +0800 清理历史 diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..57fb4d9 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,40 @@ +kind: pipeline +name: default + +steps: +- name: prepare + image: nathansamson/flutter-builder-docker:v1.0.0 + volumes: + - name: pub-cache + path: /opt/flutter/.pub-cache + commands: + - flutter packages get + +- name: analyze + image: nathansamson/flutter-builder-docker:v1.0.0 + volumes: + - name: pub-cache + path: /opt/flutter/.pub-cache + commands: + - flutter analyze + +- name: test + image: nathansamson/flutter-builder-docker:v1.0.0 + volumes: + - name: pub-cache + path: /opt/flutter/.pub-cache + commands: + - pushd example/ + - flutter test + +- name: publish-check + image: nathansamson/flutter-builder-docker:v1.0.0 + volumes: + - name: pub-cache + path: /opt/flutter/.pub-cache + commands: + - flutter packages pub publish --dry-run + +volumes: +- name: pub-cache + temp: {} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ff1b95c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* linguist-language=Dart \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c9e2ce8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.DS_Store +.dart_tool/ + +.packages +.pub/ +pubspec.lock + +build/ + +.idea/ +*.iml diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..2517d63 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b + channel: stable + +project_type: plugin diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..70c9f60 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## [0.0.1] - 2019.3.5 + +* android/ios weibo diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4101d7f --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# fake_weibo + +[![Build Status](https://cloud.drone.io/api/badges/v7lin/fake_weibo/status.svg)](https://cloud.drone.io/v7lin/fake_weibo) +[![GitHub tag](https://img.shields.io/github/tag/v7lin/fake_weibo.svg)](https://github.com/v7lin/fake_weibo/releases) + +flutter版新浪微博SDK + +## fake 系列 libraries + +1. [flutter版okhttp3](https://github.com/v7lin/fake_http) +2. [flutter版微信SDK](https://github.com/v7lin/fake_wechat) +3. [flutter版腾讯(QQ)SDK](https://github.com/v7lin/fake_tencent) +4. [flutter版新浪微博SDK](https://github.com/v7lin/fake_weibo) +5. [flutter版支付宝SDK](https://github.com/v7lin/fake_alipay) + +## android + +```` +# 不需要做任何额外接入工作 +# 混淆已打入 Library,随 Library 引用,自动添加到 apk 打包混淆 +```` + +## ios + +```` +在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id + +URL Types +weibosdk: identifier=com.weibo schemes=wb${appKey} +```` + +```` +iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。 +LSApplicationQueriesSchemes + + sinaweibo + sinaweibohd + weibosdk + weibosdk2.5 + +NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + sina.com.cn + + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSThirdPartyExceptionRequiresForwardSecrecy + + + + +```` +## flutter + +#### snapshot +```` +dependencies: + fake_weibo: + git: + url: https://github.com/v7lin/fake_weibo.git +```` + +### release +```` +latestVersion = 0.0.1 +```` + +```` +dependencies: + fake_weibo: ^${latestVersion} +```` + +### example +[示例](./example/lib/main.dart) + +## Getting Started + +This project is a starting point for a Flutter +[plug-in package](https://flutter.io/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, +samples, guidance on mobile development, and a full API reference. diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..8383c4a --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,128 @@ +# 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 + +analyzer: + strong-mode: + implicit-casts: false + # implicit-dynamic: false + + errors: + # treat missing required parameters as a warning (not a hint) + missing_required_param: warning + # treat missing returns as a warning (not a hint) + missing_return: warning + # allow having TODOs in the code + 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 + +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 diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..c6cbe56 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..44e0b02 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,45 @@ +group 'io.github.v7lin.fakeweibo' +version '1.0-SNAPSHOT' + +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + } +} + +rootProject.allprojects { + repositories { + google() + jcenter() + + // weibo + maven { + url "https://dl.bintray.com/thelasterstar/maven/" + } + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 27 + + defaultConfig { + minSdkVersion 16 + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + lintOptions { + disable 'InvalidPackage' + } +} + +dependencies { + implementation fileTree(include: ['*.jar'], dir: 'libs') + + implementation 'io.github.v7lin:weibo-android:4.3.4' +} diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..8bd86f6 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..a4ad301 --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'fake_weibo' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2f2abfe --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java b/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java new file mode 100644 index 0000000..79f2fb3 --- /dev/null +++ b/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java @@ -0,0 +1,243 @@ +package io.github.v7lin.fakeweibo; + +import android.content.Intent; +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 FakeWeiboErrorCode { + 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_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_EXPIRATIONDATE = "expirationDate"; + + 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, FakeWeiboErrorCode.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()); + map.put(ARGUMENT_KEY_RESULT_EXPIRATIONDATE, oauth2AccessToken.getExpiresTime()); + } else { + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.UNKNOWN); + } + channel.invokeMethod(METHOD_ONAUTHRESP, map); + } + + @Override + public void cancel() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.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, FakeWeiboErrorCode.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, FakeWeiboErrorCode.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)) { + ImageObject object = new ImageObject(); + object.imageData = call.argument(ARGUMENT_KEY_IMAGEDATA);// 2 * 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, FakeWeiboErrorCode.SUCCESS); + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + + @Override + public void onWbShareCancel() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.USERCANCEL); + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + + @Override + public void onWbShareFail() { + Map map = new HashMap<>(); + map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.SHARE_IN_SDK_FAILED); + channel.invokeMethod(METHOD_ONSHAREMSGRESP, map); + } + }); + } + } + return false; + } +} diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..47e0b4d --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,71 @@ +# Miscellaneous +*.class +*.lock +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# 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.* + +# 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 new file mode 100644 index 0000000..460bc20 --- /dev/null +++ b/example/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b + channel: stable + +project_type: app diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..6765301 --- /dev/null +++ b/example/README.md @@ -0,0 +1,16 @@ +# fake_weibo_example + +Demonstrates how to use the fake_weibo plugin. + +## Getting Started + +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) + +For help getting started with Flutter, view our +[online documentation](https://flutter.io/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 new file mode 100644 index 0000000..c4c4b52 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,31 @@ +# 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 + +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 \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..b37b6f7 --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,61 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 27 + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "io.github.v7lin.fakeweiboexample" + minSdkVersion 16 + targetSdkVersion 27 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + // 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 + } + } +} + +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/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..31f890e --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + 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 new file mode 100644 index 0000000..9cd00a4 --- /dev/null +++ b/example/android/app/src/main/java/io/github/v7lin/fakeweiboexample/MainActivity.java @@ -0,0 +1,13 @@ +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/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..00fa441 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..bb8a303 --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,29 @@ +buildscript { + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.2.1' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..8bd86f6 --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536M diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2819f02 --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +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 diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/example/images/icon/2.0x/ic_launcher.png b/example/images/icon/2.0x/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/example/images/icon/2.0x/ic_launcher.png differ diff --git a/example/images/icon/2.0x/timg.jpeg b/example/images/icon/2.0x/timg.jpeg new file mode 100644 index 0000000..5c2debd Binary files /dev/null and b/example/images/icon/2.0x/timg.jpeg differ diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..9367d48 --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..e8efba1 --- /dev/null +++ b/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..399e934 --- /dev/null +++ b/example/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..d077b08 --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,69 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + pods_ary = [] + 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 +end + +target 'Runner' do + # 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') + } +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9c665d8 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,589 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; + 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 */; }; + 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 */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, + 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* 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 = ""; }; + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; + 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 = ""; }; + 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 = ""; }; + 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 = ""; }; + CC78EBE1496BEBD8B37D6CBF /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, + 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + F607D74C02A3D09C94D22138 /* libPods-Runner.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 118CEF9B5D8D03B56D5D7C1F /* Pods */ = { + isa = PBXGroup; + children = ( + ); + name = Pods; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, + 3B80C3931E831B6300D905FE /* App.framework */, + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEBA1CF902C7004384FC /* Flutter.framework */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 118CEF9B5D8D03B56D5D7C1F /* Pods */, + BC7D72E583FD7697E09D7784 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, + 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 97C146F21CF9000F007C117D /* main.m */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + BC7D72E583FD7697E09D7784 /* Frameworks */ = { + isa = PBXGroup; + children = ( + CC78EBE1496BEBD8B37D6CBF /* libPods-Runner.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 5E40D85FABB1650818BB4959 /* [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 */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0910; + ORGANIZATIONNAME = "The Chromium Authors"; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + DevelopmentTeam = 78W43A3TE2; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 2E75A410B195E117A49D1E82 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_ROOT}/Weibo_SDK/libWeiboSDK/WeiboSDK.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/WeiboSDK.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; + }; + 5E40D85FABB1650818BB4959 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + BA5C6C2059F783B8F3A1D718 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", + "${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, + 97C146F31CF9000F007C117D /* main.m in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = 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_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 78W43A3TE2; + ENABLE_BITCODE = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.fakeWeiboExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..786d6aa --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/example/ios/Runner/AppDelegate.h b/example/ios/Runner/AppDelegate.h new file mode 100644 index 0000000..36e21bb --- /dev/null +++ b/example/ios/Runner/AppDelegate.h @@ -0,0 +1,6 @@ +#import +#import + +@interface AppDelegate : FlutterAppDelegate + +@end diff --git a/example/ios/Runner/AppDelegate.m b/example/ios/Runner/AppDelegate.m new file mode 100644 index 0000000..59a72e9 --- /dev/null +++ b/example/ios/Runner/AppDelegate.m @@ -0,0 +1,13 @@ +#include "AppDelegate.h" +#include "GeneratedPluginRegistrant.h" + +@implementation AppDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [GeneratedPluginRegistrant registerWithRegistry:self]; + // Override point for customization after application launch. + return [super application:application didFinishLaunchingWithOptions:launchOptions]; +} + +@end diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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 new file mode 100644 index 0000000..3d43d11 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..28c6bf0 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..f091b6b Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cde121 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..d0ef06e Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..dcdc230 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..2ccbfd9 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..c8f9ed8 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..a6d6b86 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..75b2d16 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..c4df70d Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..6a84f41 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..d0e1f58 Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 0000000..b4c975c --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,84 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + fake_weibo_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLName + com.weibo + CFBundleURLSchemes + + wb3393861383 + + + + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSApplicationQueriesSchemes + + sinaweibo + sinaweibohd + weibosdk + weibosdk2.5 + + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSExceptionDomains + + sina.com.cn + + NSExceptionMinimumTLSVersion + TLSv1.0 + NSIncludesSubdomains + + NSThirdPartyExceptionAllowsInsecureHTTPLoads + + NSThirdPartyExceptionRequiresForwardSecrecy + + + + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/example/ios/Runner/main.m b/example/ios/Runner/main.m new file mode 100644 index 0000000..dff6597 --- /dev/null +++ b/example/ios/Runner/main.m @@ -0,0 +1,9 @@ +#import +#import +#import "AppDelegate.h" + +int main(int argc, char* argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..ed30a52 --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,180 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:fake_weibo/fake_weibo.dart'; + +const String _weiboAppKey = '3393861383'; + +void main() { + runZoned(() { + runApp(MyApp()); + }, onError: (dynamic error, dynamic stack) { + print(error); + print(stack); + }); + + if (Platform.isAndroid) { + SystemUiOverlayStyle systemUiOverlayStyle = + const SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + } +} + +class MyApp extends StatelessWidget { + @override + Widget build(BuildContext context) { + FakeWeibo weibo = new FakeWeibo( + appKey: _weiboAppKey, + scope: [ + FakeWeiboScope.ALL, + ], + ); + weibo.registerApp(); + return new FakeWeiboProvider( + weibo: weibo, + child: new MaterialApp( + home: new Home( + weibo: weibo, + ), + ), + ); + } +} + +class Home extends StatefulWidget { + Home({Key key, @required this.weibo}) : super(key: key); + + final FakeWeibo weibo; + + @override + State createState() { + return new _HomeState(); + } +} + +class _HomeState extends State { + StreamSubscription _auth; + StreamSubscription _share; + + FakeWeiboAuthResp _authResp; + + @override + void initState() { + super.initState(); + _auth = widget.weibo.authResp().listen(_listenAuth); + _share = widget.weibo.shareMsgResp().listen(_listenShareMsg); + } + + void _listenAuth(FakeWeiboAuthResp resp) { + _authResp = resp; + String content = 'auth: ${resp.errorCode}'; + _showTips('登录', content); + } + + void _listenShareMsg(FakeWeiboShareMsgResp resp) { + String content = 'share: ${resp.errorCode}'; + _showTips('分享', content); + } + + @override + void dispose() { + if (_auth != null) { + _auth.cancel(); + } + if (_share != null) { + _share.cancel(); + } + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text('Fake Weibo Demo'), + ), + body: new ListView( + children: [ + new ListTile( + title: new Text('环境检查'), + onTap: () async { + String content = + 'weibo: ${await widget.weibo.isWeiboInstalled()}'; + _showTips('环境检查', content); + }, + ), + new ListTile( + title: new Text('登录'), + onTap: () { + widget.weibo.auth(); + }, + ), + new ListTile( + title: new Text('用户信息'), + onTap: () async { + if (_authResp != null && + _authResp.errorCode == FakeWeiboErrorCode.SUCCESS) { + FakeWeiboApiUserResp userResp = await widget.weibo + .getUserInfo(appkey: _weiboAppKey, userId: _authResp.userId, accessToken: _authResp.accessToken); + if (userResp != null && userResp.errorCode == FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS) { + _showTips('用户信息', '${userResp.screenName}\n${userResp.description}\n${userResp.location}\n${userResp.profileImageUrl}'); + } else { + _showTips('用户信息', '获取用户信息失败\n${userResp.errorCode}:${userResp.error}'); + } + } + }, + ), + new ListTile( + title: new Text('文字分享'), + onTap: () { + widget.weibo.shareText( + text: 'Share Text', + ); + }, + ), + new ListTile( + title: new Text('图片分享'), + onTap: () async { + AssetImage image = new AssetImage('images/icon/timg.jpeg'); + AssetBundleImageKey key = + await image.obtainKey(createLocalImageConfiguration(context)); + ByteData imageData = await key.bundle.load(key.name); + await widget.weibo.shareImage( + imageData: imageData.buffer.asUint8List(), + ); + }, + ), + new ListTile( + title: new Text('网页分享'), + onTap: () async { + AssetImage image = new AssetImage('images/icon/ic_launcher.png'); + AssetBundleImageKey key = + await image.obtainKey(createLocalImageConfiguration(context)); + ByteData thumbData = await key.bundle.load(key.name); + await widget.weibo.shareWebpage( + title: 'title', + description: 'share webpage', + thumbData: thumbData.buffer.asUint8List(), + webpageUrl: 'https://www.baidu.com', + ); + }, + ), + ], + ), + ); + } + + void _showTips(String title, String content) { + showDialog( + context: context, + builder: (BuildContext context) { + return new AlertDialog( + title: new Text(title), + content: new Text(content), + ); + }, + ); + } +} diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..1145e2d --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,65 @@ +name: fake_weibo_example +description: Demonstrates how to use the fake_weibo plugin. +publish_to: 'none' + +environment: + sdk: ">=2.0.0-dev.68.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^0.1.2 + + fake_weibo: + path: ../ + +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 + +# The following section is specific to Flutter. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + 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 + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/assets-and-images/#resolution-aware. + + # For details regarding adding assets from package dependencies, see + # https://flutter.io/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 + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.io/custom-fonts/#from-packages diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 0000000..baa5890 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,10 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +void main() { + +} diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..710ec6c --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,36 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ios/Classes/FakeWeiboPlugin.h b/ios/Classes/FakeWeiboPlugin.h new file mode 100644 index 0000000..0391846 --- /dev/null +++ b/ios/Classes/FakeWeiboPlugin.h @@ -0,0 +1,4 @@ +#import + +@interface FakeWeiboPlugin : NSObject +@end diff --git a/ios/Classes/FakeWeiboPlugin.m b/ios/Classes/FakeWeiboPlugin.m new file mode 100644 index 0000000..86c8075 --- /dev/null +++ b/ios/Classes/FakeWeiboPlugin.m @@ -0,0 +1,163 @@ +#import "FakeWeiboPlugin.h" +#import + +@interface FakeWeiboPlugin () + +@end + +@implementation FakeWeiboPlugin { + 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]; +} + +static NSString * const METHOD_REGISTERAPP = @"registerApp"; +static NSString * const METHOD_ISWEIBOINSTALLED = @"isWeiboInstalled"; +static NSString * const METHOD_AUTH = @"auth"; +static NSString * const METHOD_SHARETEXT = @"shareText"; +static NSString * const METHOD_SHAREIMAGE = @"shareImage"; +static NSString * const METHOD_SHAREWEBPAGE = @"shareWebpage"; + +static NSString * const METHOD_ONAUTHRESP = @"onAuthResp"; +static NSString * const METHOD_ONSHAREMSGRESP = @"onShareMsgResp"; + +static NSString * const ARGUMENT_KEY_APPKEY = @"appKey"; +static NSString * const ARGUMENT_KEY_SCOPE = @"scope"; +static NSString * const ARGUMENT_KEY_REDIRECTURL = @"redirectUrl"; +static NSString * const ARGUMENT_KEY_TEXT = @"text"; +static NSString * const ARGUMENT_KEY_TITLE = @"title"; +static NSString * const ARGUMENT_KEY_DESCRIPTION = @"description"; +static NSString * const ARGUMENT_KEY_THUMBDATA = @"thumbData"; +static NSString * const ARGUMENT_KEY_IMAGEDATA = @"imageData"; +static NSString * const ARGUMENT_KEY_WEBPAGEURL = @"webpageUrl"; + +static NSString * const ARGUMENT_KEY_RESULT_ERRORCODE = @"errorCode"; +static NSString * const ARGUMENT_KEY_RESULT_ERRORMESSAGE = @"errorMessage"; +static NSString * const ARGUMENT_KEY_RESULT_USERID = @"userId"; +static NSString * const ARGUMENT_KEY_RESULT_ACCESSTOKEN = @"accessToken"; +static NSString * const ARGUMENT_KEY_RESULT_REFRESHTOKEN = @"refreshToken"; +static NSString * const ARGUMENT_KEY_RESULT_EXPIRATIONDATE = @"expirationDate"; + +-(instancetype)initWithChannel:(FlutterMethodChannel *)channel { + self = [super init]; + if (self) { + _channel = channel; + } + 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)handleAuthCall:(FlutterMethodCall*)call result:(FlutterResult)result { + WBAuthorizeRequest * request = [WBAuthorizeRequest request]; + request.scope = call.arguments[ARGUMENT_KEY_SCOPE]; + request.redirectURI = call.arguments[ARGUMENT_KEY_REDIRECTURL]; + request.shouldShowWebViewForAuthIfCannotSSO = YES; + request.shouldOpenWeiboAppInstallPageIfNotInstalled = NO; + [WeiboSDK sendRequest:request]; + result(nil); +} + +-(void)handleShareTextCall:(FlutterMethodCall*)call result:(FlutterResult)result { + WBSendMessageToWeiboRequest * request = [WBSendMessageToWeiboRequest request]; + WBMessageObject * message = [WBMessageObject message]; + message.text = call.arguments[ARGUMENT_KEY_TEXT]; + request.message = message; + [WeiboSDK sendRequest:request]; + result(nil); +} + +-(void)handleShareMediaCall:(FlutterMethodCall*)call result:(FlutterResult)result { + WBSendMessageToWeiboRequest * request = [WBSendMessageToWeiboRequest request]; + WBMessageObject * message = [WBMessageObject message]; + if ([METHOD_SHAREIMAGE isEqualToString:call.method]) { + WBImageObject * object = [WBImageObject object]; + FlutterStandardTypedData * imageData = call.arguments[ARGUMENT_KEY_IMAGEDATA]; + object.imageData = imageData.data; + message.imageObject = object; + } else if ([METHOD_SHAREWEBPAGE isEqualToString:call.method]) { + WBWebpageObject * object = [WBWebpageObject object]; + object.objectID = [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; + object.title = call.arguments[ARGUMENT_KEY_TITLE]; + object.description = call.arguments[ARGUMENT_KEY_DESCRIPTION]; + FlutterStandardTypedData * thumbData = call.arguments[ARGUMENT_KEY_THUMBDATA]; + if (thumbData != nil) { + object.thumbnailData = thumbData.data; + } + object.webpageUrl = call.arguments[ARGUMENT_KEY_WEBPAGEURL]; + message.mediaObject = object; + } + request.message = message; + [WeiboSDK sendRequest:request]; + result(nil); +} + +# pragma mark - AppDelegate + +-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { + return [WeiboSDK handleOpenURL:url delegate:self]; +} + +-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { + return [WeiboSDK handleOpenURL:url delegate:self]; +} + +- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { + return [WeiboSDK handleOpenURL:url delegate:self]; +} + +# pragma mark - WeiboSDKDelegate + +-(void)didReceiveWeiboRequest:(WBBaseRequest *)request { + +} + +-(void)didReceiveWeiboResponse:(WBBaseResponse *)response { + NSMutableDictionary * dictionary = [NSMutableDictionary dictionary]; + [dictionary setValue:[NSNumber numberWithInteger:response.statusCode] forKey:ARGUMENT_KEY_RESULT_ERRORCODE]; + if ([response isKindOfClass:[WBAuthorizeResponse class]]) { + if (response.statusCode == WeiboSDKResponseStatusCodeSuccess) { + WBAuthorizeResponse * authorizeResponse = (WBAuthorizeResponse *) response; + NSString * userId = authorizeResponse.userID; + NSString * accessToken = authorizeResponse.accessToken; + NSString * refreshToken = authorizeResponse.refreshToken; + long long expirationDate = authorizeResponse.expirationDate.timeIntervalSince1970 * 1000; + [dictionary setValue:userId forKey:ARGUMENT_KEY_RESULT_USERID]; + [dictionary setValue:accessToken forKey:ARGUMENT_KEY_RESULT_ACCESSTOKEN]; + [dictionary setValue:refreshToken forKey:ARGUMENT_KEY_RESULT_REFRESHTOKEN]; + [dictionary setValue:[NSNumber numberWithLongLong:expirationDate] forKey:ARGUMENT_KEY_RESULT_EXPIRATIONDATE]; + } + [_channel invokeMethod:METHOD_ONAUTHRESP arguments:dictionary]; + } else if ([response isKindOfClass:[WBSendMessageToWeiboResponse class]]) { + if (response.statusCode == WeiboSDKResponseStatusCodeSuccess) { + WBSendMessageToWeiboResponse * sendMessageToWeiboResponse = (WBSendMessageToWeiboResponse *) response; + } + [_channel invokeMethod:METHOD_ONSHAREMSGRESP arguments:dictionary]; + } +} + +@end diff --git a/ios/fake_weibo.podspec b/ios/fake_weibo.podspec new file mode 100644 index 0000000..be54436 --- /dev/null +++ b/ios/fake_weibo.podspec @@ -0,0 +1,23 @@ +# +# 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.static_framework = true + s.dependency 'Flutter' + s.dependency 'Weibo_SDK', '~> 3.2.3' + + s.ios.deployment_target = '8.0' +end + diff --git a/lib/fake_weibo.dart b/lib/fake_weibo.dart new file mode 100644 index 0000000..eda5095 --- /dev/null +++ b/lib/fake_weibo.dart @@ -0,0 +1,529 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; +import 'package:meta/meta.dart'; + +class FakeWeiboScope { + FakeWeiboScope._(); + + static const String EMAIL = 'email'; + static const String DIRECT_MESSAGES_READ = 'direct_messages_read'; + static const String DIRECT_MESSAGES_WRITE = 'direct_messages_write'; + static const String FRIENDSHIPS_GROUPS_READ = 'friendships_groups_read'; + static const String FRIENDSHIPS_GROUPS_WRITE = 'friendships_groups_write'; + static const String STATUSES_TO_ME_READ = 'statuses_to_me_read'; + static const String FOLLOW_APP_OFFICIAL_MICROBLOG = + 'follow_app_official_microblog'; + static const String INVITATION_WRITE = 'invitation_write'; + static const String ALL = 'all'; +} + +class FakeWeiboErrorCode { + FakeWeiboErrorCode._(); + + /// 成功 + static const int SUCCESS = 0; + + /// 用户取消发送 + static const int USERCANCEL = -1; + + /// 发送失败 + static const int SENT_FAIL = -2; + + /// 授权失败 + static const int AUTH_DENY = -3; + + /// 用户取消安装微博客户端 + static const int USERCANCEL_INSTALL = -4; + + /// 支付失败 + static const int PAY_FAIL = -5; + + /// 分享失败 详情见response UserInfo + static const int SHARE_IN_SDK_FAILED = -8; + + /// 不支持的请求 + static const int UNSUPPORT = -99; + + /// 未知 + static const int UNKNOWN = -100; + + /// sso package or sign error + static const int SSO_PKG_SIGN_ERROR = 21338; +} + +abstract class FakeWeiboBaseResp { + FakeWeiboBaseResp({ + @required this.errorCode, + this.errorMessage, + }); + + final int errorCode; + final String errorMessage; +} + +class FakeWeiboAuthResp extends FakeWeiboBaseResp { + FakeWeiboAuthResp._({ + @required int errorCode, + String errorMessage, + this.userId, + this.accessToken, + this.refreshToken, + this.expirationDate, + }) : super( + errorCode: errorCode, + errorMessage: errorMessage, + ); + + final String userId; + final String accessToken; + final String refreshToken; + final int expirationDate; +} + +class FakeWeiboShareMsgResp extends FakeWeiboBaseResp { + FakeWeiboShareMsgResp._({ + @required int errorCode, + String errorMessage, + }) : super( + errorCode: errorCode, + errorMessage: errorMessage, + ); +} + +abstract class FakeWeiboApiBaseResp { + FakeWeiboApiBaseResp({ + @required this.errorCode, + this.error, + this.request, + }); + + static const String KEY_ERROR_CODE = 'error_code'; + static const String KEY_ERROR = 'error'; + static const String KEY_REQUEST = 'request'; + + static const int ERROR_CODE_SUCCESS = 0; + + /// https://open.weibo.com/wiki/Help/error + final int errorCode; + final String error; + final String request; +} + +class FakeWeiboApiUserResp extends FakeWeiboApiBaseResp { + FakeWeiboApiUserResp._({ + int errorCode, + String error, + String request, + this.id, + this.idstr, + this.screenName, + this.name, + this.province, + this.city, + this.location, + this.description, + this.url, + this.profileImageUrl, + this.profileUrl, + this.domain, + this.weihao, + this.gender, + this.verified, + this.avatarLarge, + this.avatarHD, + }) : super(errorCode: errorCode, error: error, request: request); + + static const String KEY_ID = 'id'; + static const String KEY_ID_STR = 'idstr'; + static const String KEY_SCREEN_NAME = 'screen_name'; + static const String KEY_NAME = 'name'; + static const String KEY_PROVINCE = 'province'; + static const String KEY_CITY = 'city'; + static const String KEY_LOCATION = 'location'; + static const String KEY_DESCRIPTION = 'description'; + static const String KEY_URL = 'url'; + static const String KEY_PROFILE_IMAGE_URL = 'profile_image_url'; + static const String KEY_PROFILE_URL = 'profile_url'; + static const String KEY_DOMAIN = 'domain'; + static const String KEY_WEIHAO = 'weihao'; + static const String KEY_GENDER = 'gender'; + static const String KEY_VERIFIED = 'verified'; + static const String KEY_AVATAR_LARGE = 'avatar_large'; + static const String KEY_AVATAR_HD = 'avatar_hd'; + + /// 用户UID(int64) + final int id; + + /// 字符串型的用户 UID + final String idstr; + + /// 用户昵称 + final String screenName; + + /// 友好显示名称 + final String name; + + /// 用户所在省级ID + final String province; + + /// 用户所在城市ID + final String city; + + /// 用户所在地 + final String location; + + /// 用户个人描述 + final String description; + + /// 用户博客地址 + final String url; + + /// 用户头像地址,50×50像素 + final String profileImageUrl; + + /// 用户的微博统一URL地址 + final String profileUrl; + + /// 用户的个性化域名 + final String domain; + + /// 用户的微号 + final String weihao; + + /// 性别,m:男、f:女、n:未知 + final String gender; + +// /// 粉丝数 +// final int followers_count; + +// /// 关注数 +// final int friends_count; + +// /// 微博数 +// final int statuses_count; + +// /// 收藏数 +// final int favourites_count; + +// /// 用户创建(注册)时间 +// final String created_at; + +// /// 暂未支持 +// final bool following; + +// /// 是否允许所有人给我发私信,true:是,false:否 +// final bool allow_all_act_msg; + +// /// 是否允许标识用户的地理位置,true:是,false:否 +// final bool geo_enabled; + + /// 是否是微博认证用户,即加V用户,true:是,false:否 + final bool verified; + +// /// 暂未支持 +// final int verified_type; + +// /// 用户备注信息,只有在查询用户关系时才返回此字段 +// final String remark; + +// /// 用户的最近一条微博信息字段 +// final dynamic status; + +// /// 是否允许所有人对我的微博进行评论,true:是,false:否 +// final bool allow_all_comment; + + /// 用户大头像地址 + final String avatarLarge; + + /// 用户高清大头像地址 + final String avatarHD; + +// /// 认证原因 +// final String verified_reason; + +// /// 该用户是否关注当前登录用户,true:是,false:否 +// final bool follow_me; + +// /// 用户的在线状态,0:不在线、1:在线 +// final int online_status; + +// /// 用户的互粉数 +// final int bi_followers_count; + +// /// 用户当前的语言版本,zh-cn:简体中文,zh-tw:繁体中文,en:英语 +// final String lang; + +// /// 注意:以下字段暂时不清楚具体含义,OpenAPI 说明文档暂时没有同步更新对应字段 +// final String star; +// final String mbtype; +// final String mbrank; +// final String block_word; +} + +class FakeWeibo { + FakeWeibo({ + @required String appKey, + @required List scope, + String redirectUrl = _DEFAULT_REDIRECTURL, + }) : assert(appKey != null && appKey.isNotEmpty), + assert(scope != null && scope.isNotEmpty), + _appKey = appKey, + _scope = scope, + _redirectUrl = redirectUrl; + + static const String _METHOD_REGISTERAPP = 'registerApp'; + static const String _METHOD_ISWEIBOINSTALLED = 'isWeiboInstalled'; + static const String _METHOD_AUTH = 'auth'; + static const String _METHOD_SHARETEXT = 'shareText'; + static const String _METHOD_SHAREIMAGE = 'shareImage'; + static const String _METHOD_SHAREWEBPAGE = 'shareWebpage'; + + static const String _METHOD_ONAUTHRESP = 'onAuthResp'; + static const String _METHOD_ONSHAREMSGRESP = 'onShareMsgResp'; + + static const String _ARGUMENT_KEY_APPKEY = 'appKey'; + static const String _ARGUMENT_KEY_SCOPE = 'scope'; + static const String _ARGUMENT_KEY_REDIRECTURL = 'redirectUrl'; + static const String _ARGUMENT_KEY_TEXT = 'text'; + static const String _ARGUMENT_KEY_TITLE = 'title'; + static const String _ARGUMENT_KEY_DESCRIPTION = 'description'; + static const String _ARGUMENT_KEY_THUMBDATA = 'thumbData'; + static const String _ARGUMENT_KEY_IMAGEDATA = 'imageData'; + static const String _ARGUMENT_KEY_WEBPAGEURL = 'webpageUrl'; + + static const String _ARGUMENT_KEY_RESULT_ERRORCODE = "errorCode"; + static const String _ARGUMENT_KEY_RESULT_ERRORMESSAGE = "errorMessage"; + static const String _ARGUMENT_KEY_RESULT_USERID = 'userId'; + static const String _ARGUMENT_KEY_RESULT_ACCESSTOKEN = 'accessToken'; + static const String _ARGUMENT_KEY_RESULT_REFRESHTOKEN = 'refreshToken'; + static const String _ARGUMENT_KEY_RESULT_EXPIRATIONDATE = 'expirationDate'; + + static const String _DEFAULT_REDIRECTURL = + 'https://api.weibo.com/oauth2/default.html'; + + static const MethodChannel _channel = + MethodChannel('v7lin.github.io/fake_weibo'); + + final String _appKey; + final List _scope; + + /// 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置 + final String _redirectUrl; + + final StreamController _authRespStreamController = + StreamController.broadcast(); + + final StreamController _shareMsgRespStreamController = + StreamController.broadcast(); + + Future registerApp() { + _channel.setMethodCallHandler(_handleMethod); + return _channel.invokeMethod( + _METHOD_REGISTERAPP, + { + _ARGUMENT_KEY_APPKEY: _appKey, + _ARGUMENT_KEY_SCOPE: _scope.join(','), + _ARGUMENT_KEY_REDIRECTURL: _redirectUrl, + }, + ); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case _METHOD_ONAUTHRESP: + _authRespStreamController.add(FakeWeiboAuthResp._( + errorCode: call.arguments[_ARGUMENT_KEY_RESULT_ERRORCODE] as int, + errorMessage: call.arguments[_ARGUMENT_KEY_RESULT_ERRORMESSAGE] as String, + userId: call.arguments[_ARGUMENT_KEY_RESULT_USERID] as String, + accessToken: + call.arguments[_ARGUMENT_KEY_RESULT_ACCESSTOKEN] as String, + refreshToken: + call.arguments[_ARGUMENT_KEY_RESULT_REFRESHTOKEN] as String, + expirationDate: + call.arguments[_ARGUMENT_KEY_RESULT_EXPIRATIONDATE] as int, + )); + break; + case _METHOD_ONSHAREMSGRESP: + _shareMsgRespStreamController.add(FakeWeiboShareMsgResp._( + errorCode: call.arguments[_ARGUMENT_KEY_RESULT_ERRORCODE] as int, + errorMessage: call.arguments[_ARGUMENT_KEY_RESULT_ERRORMESSAGE] as String, + )); + break; + } + } + + Stream authResp() { + return _authRespStreamController.stream; + } + + Stream shareMsgResp() { + return _shareMsgRespStreamController.stream; + } + + Future isWeiboInstalled() async { + return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool; + } + + Future auth() { + return _channel.invokeMethod( + _METHOD_AUTH, + { + _ARGUMENT_KEY_APPKEY: _appKey, + _ARGUMENT_KEY_SCOPE: _scope.join(','), + _ARGUMENT_KEY_REDIRECTURL: _redirectUrl, + }, + ); + } + + Future getUserInfo({ + @required String appkey, + @required String userId, + @required String accessToken, + }) { + assert(userId != null && userId.isNotEmpty); + assert(accessToken != null && accessToken.isNotEmpty); + Map params = { + 'uid': userId, + }; + return HttpClient() + .getUrl(_encodeUrl('https://api.weibo.com/2/users/show.json', appkey, + accessToken, params)) + .then((HttpClientRequest request) { + return request.close(); + }).then((HttpClientResponse response) async { + if (response.statusCode == HttpStatus.ok) { + String content = await utf8.decodeStream(response); + Map map = json.decode(content); + int errorCode = map.containsKey(FakeWeiboApiBaseResp.KEY_ERROR_CODE) + ? map[FakeWeiboApiBaseResp.KEY_ERROR_CODE] + : FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS; + if (errorCode == FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS) { + return FakeWeiboApiUserResp._( + errorCode: errorCode, + id: map[FakeWeiboApiUserResp.KEY_ID] as int, + idstr: map[FakeWeiboApiUserResp.KEY_ID_STR] as String, + screenName: map[FakeWeiboApiUserResp.KEY_SCREEN_NAME] as String, + name: map[FakeWeiboApiUserResp.KEY_NAME] as String, + province: map[FakeWeiboApiUserResp.KEY_PROVINCE] as String, + city: map[FakeWeiboApiUserResp.KEY_CITY] as String, + location: map[FakeWeiboApiUserResp.KEY_LOCATION] as String, + description: map[FakeWeiboApiUserResp.KEY_DESCRIPTION] as String, + url: map[FakeWeiboApiUserResp.KEY_URL] as String, + profileImageUrl: + map[FakeWeiboApiUserResp.KEY_PROFILE_IMAGE_URL] as String, + profileUrl: map[FakeWeiboApiUserResp.KEY_PROFILE_URL] as String, + domain: map[FakeWeiboApiUserResp.KEY_DOMAIN] as String, + weihao: map[FakeWeiboApiUserResp.KEY_WEIHAO] as String, + gender: map[FakeWeiboApiUserResp.KEY_GENDER] as String, + verified: map[FakeWeiboApiUserResp.KEY_VERIFIED] as bool, + avatarLarge: map[FakeWeiboApiUserResp.KEY_AVATAR_LARGE] as String, + avatarHD: map[FakeWeiboApiUserResp.KEY_AVATAR_HD] as String, + ); + } else { + return FakeWeiboApiUserResp._( + errorCode: errorCode, + error: map[FakeWeiboApiBaseResp.KEY_ERROR] as String, + request: map[FakeWeiboApiBaseResp.KEY_REQUEST] as String, + ); + } + } + throw HttpException( + 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); + }); + } + + Uri _encodeUrl( + String baseUrl, + String appkey, + String accessToken, + Map params, + ) { + params.putIfAbsent('source', () => appkey); + params.putIfAbsent('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]); + }); + + return baseUri.replace(queryParameters: queryParametersAll); + } + + Future shareText({ + @required String text, + }) { + assert(text != null && text.isNotEmpty && text.length <= 1024); + return _channel.invokeMethod( + _METHOD_SHARETEXT, + { + _ARGUMENT_KEY_TEXT: text, + }, + ); + } + + Future shareImage({ + @required Uint8List imageData, + }) { + assert(imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024); + return _channel.invokeMethod( + _METHOD_SHAREIMAGE, + { + _ARGUMENT_KEY_IMAGEDATA: imageData, + }, + ); + } + + Future shareWebpage({ + @required String title, + @required String description, + @required Uint8List thumbData, + @required String webpageUrl, + }) { + assert(title != null && title.isNotEmpty && title.length <= 512); + assert(description != null && + description.isNotEmpty && + description.length <= 1024); + assert(thumbData != null && thumbData.lengthInBytes <= 32 * 1024); + assert(webpageUrl != null && + webpageUrl.isNotEmpty && + webpageUrl.length <= 255); + return _channel.invokeMethod( + _METHOD_SHAREWEBPAGE, + { + _ARGUMENT_KEY_TITLE: title, + _ARGUMENT_KEY_DESCRIPTION: description, + _ARGUMENT_KEY_THUMBDATA: thumbData, + _ARGUMENT_KEY_WEBPAGEURL: webpageUrl, + }, + ); + } +} + +class FakeWeiboProvider extends InheritedWidget { + FakeWeiboProvider({ + Key key, + @required this.weibo, + @required Widget child, + }) : super(key: key, child: child); + + final FakeWeibo weibo; + + @override + bool updateShouldNotify(InheritedWidget oldWidget) { + FakeWeiboProvider oldProvider = oldWidget as FakeWeiboProvider; + return weibo != oldProvider.weibo; + } + + static FakeWeiboProvider of(BuildContext context) { + return context.inheritFromWidgetOfExactType(FakeWeiboProvider) + as FakeWeiboProvider; + } +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..c3395e0 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,64 @@ +name: fake_weibo +description: A powerful weibo plugin for Flutter. +version: 0.0.1 +author: v7lin +homepage: https://github.com/v7lin/fake_weibo + +environment: + sdk: ">=2.0.0-dev.68.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + meta: ^1.1.6 + +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 + +# 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 + # 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 + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - 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 + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.io/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 + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.io/custom-fonts/#from-packages