├── .gitattributes ├── .github └── workflows │ ├── build.yml │ └── publish.yml ├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android ├── .gitignore ├── build.gradle ├── settings.gradle └── src │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── io │ │ │ └── github │ │ │ └── v7lin │ │ │ └── link_kit │ │ │ ├── LinkCallbackActivity.java │ │ │ └── LinkKitPlugin.java │ └── res │ │ └── values │ │ └── themes.xml │ └── vendor │ └── AndroidManifest.xml ├── example ├── .gitignore ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── io │ │ │ │ │ └── github │ │ │ │ │ └── v7lin │ │ │ │ │ └── link_kit_example │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Podfile │ ├── Podfile.lock │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── Runner.entitlements │ │ └── main.m ├── lib │ └── main.dart ├── pubspec.lock ├── pubspec.yaml └── test │ └── widget_test.dart ├── ios ├── .clang-format ├── .gitignore ├── Assets │ └── .gitkeep ├── Classes │ ├── LinkKitPlugin.h │ └── LinkKitPlugin.m ├── link_kit.podspec └── link_setup.rb ├── lib ├── link_kit.dart ├── link_kit_platform_interface.dart └── src │ ├── link_kit_method_channel.dart │ └── link_kit_platform_interface.dart ├── pubspec.yaml └── test ├── link_kit_method_channel_test.dart └── link_kit_test.dart /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-language=Dart -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build_ios: 7 | name: Build iOS on ${{ matrix.os }} 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [macos-latest] 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: subosito/flutter-action@v2 15 | with: 16 | channel: 'stable' 17 | - name: Run llvm/clang-format@shell 18 | run: | 19 | brew install clang-format 20 | - name: Run ruby/plist@shell 21 | run: | 22 | gem install plist 23 | - run: clang-format -style=file -i ios/Classes/*.h ios/Classes/*.m --dry-run --Werror 24 | - run: flutter --version 25 | - run: flutter pub get 26 | - run: dart format --set-exit-if-changed . 27 | - run: flutter pub publish --dry-run 28 | - run: flutter analyze lib example/lib 29 | - run: cd example; flutter build ios --no-codesign 30 | 31 | build_android: 32 | name: Build Android on ${{ matrix.os }} 33 | runs-on: ${{ matrix.os }} 34 | strategy: 35 | fail-fast: false 36 | matrix: 37 | os: [windows-latest, ubuntu-latest, macos-latest] 38 | steps: 39 | - uses: actions/checkout@v3 40 | - uses: actions/setup-java@v2 41 | with: 42 | distribution: 'zulu' 43 | java-version: '11' 44 | - uses: subosito/flutter-action@v2 45 | with: 46 | channel: 'stable' 47 | - run: flutter --version 48 | - run: flutter pub get 49 | - run: dart format --set-exit-if-changed . 50 | - run: flutter pub publish --dry-run 51 | - run: flutter analyze lib example/lib 52 | - run: cd example; flutter build apk --debug 53 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: subosito/flutter-action@v2 15 | with: 16 | channel: 'stable' 17 | - name: Run pub.dev/inject-credentials@shell 18 | env: 19 | CREDENTIALS: ${{ secrets.CREDENTIALS_JSON }} 20 | run: | 21 | if [ -z $PUB_CACHE ];then 22 | PUB_CACHE=~/.pub-cache 23 | fi 24 | mkdir -p $PUB_CACHE 25 | echo $CREDENTIALS > $PUB_CACHE/credentials.json 26 | - run: flutter --version 27 | - run: flutter pub get 28 | - run: dart format --set-exit-if-changed . 29 | - run: echo "y" | flutter pub publish 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | .packages 30 | build/ 31 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: f1875d570e39de09040c8f79aa13cc56baab8db1 8 | channel: stable 9 | 10 | project_type: plugin 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 17 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 18 | - platform: android 19 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 20 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 21 | - platform: ios 22 | create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 23 | base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.1 2 | 3 | * 优化 4 | 5 | ## 1.0.0 6 | 7 | * break change 8 | * Android: 提高新手配置友好度,不在需要手动配置 9 | * iOS: 提高新手配置友好度,不在需要手动配置 10 | 11 | ## 0.0.3 12 | 13 | * Android App Links 14 | * iOS Universal Links 15 | * fix: 16 | * Android: 「queryIntentActivities」引起「小米审核」误判「获取安装列表」 17 | > 详见[link_kit#Flutter](./README.md#flutter) 18 | 19 | ## 0.0.2 20 | 21 | * support multiple schemes. 22 | 23 | ## 0.0.1 24 | 25 | * initial release. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # link_kit 2 | 3 | Flutter plugin for Deep Link/App Link/Universal Links. 4 | 5 | ## ⚠️⚠️⚠️ 6 | 7 | * link_kit 1.0.0 配置并不与 0.0.x 兼容,请手动删除 0.0.x 配置 8 | * 因为 Android 的 manifestPlaceholders 能力有限,又懒得写需要兼容各版本的 Gradle 插件,所以默认只支持配置一个 DeepLink/AppLink/UniversalLink 9 | 10 | ## Android 11 | 12 | #### 文档 13 | 14 | * [创建指向应用内容的深层链接](https://developer.android.com/training/app-links/deep-linking) 15 | * [添加 Android 应用链接](https://developer.android.com/studio/write/app-link-indexing.html) 16 | * [simonmarquis/Android App Linking](https://simonmarquis.github.io/Android-App-Linking/) 17 | * [Statement List Generator and Tester](https://developers.google.com/digital-asset-links/tools/generator) 18 | 19 | #### 配置 20 | 21 | ``` 22 | # 不需要做任何额外接入工作 23 | # 配置已集成到脚本里 24 | ``` 25 | 26 | * App Links 27 | 28 | assetlinks.json - 通过 https://${your applinks domain}/.well-known/assetlinks.json 链接可访问 29 | 30 | 示例: 31 | 32 | https://${your applinks domain}/universal_link/${example_app}/link_kit/ 33 | 34 | ```json 35 | [ 36 | { 37 | "relation": [ 38 | "delegate_permission/common.handle_all_urls" 39 | ], 40 | "target": { 41 | "namespace": "android_app", 42 | "package_name": "your_app_package_name", 43 | "sha256_cert_fingerprints": [ 44 | "your_app_package_fingerprint_sha256" 45 | ] 46 | } 47 | } 48 | ] 49 | ``` 50 | 51 | > [获取 Android 签名信息](https://github.com/RxReader/wechat_kit#android) 52 | 53 | #### 测试 54 | 55 | ```shell 56 | # Deep Link 57 | adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "flk:///power" 58 | ``` 59 | 60 | ```shell 61 | # App Link 62 | adb shell am start -a android.intent.action.VIEW -c android.intent.category.BROWSABLE -d "https://www.yourdomain.com/universal_link/example_app/link_kit/power" 63 | ``` 64 | 65 | ## iOS 66 | 67 | #### 文档 68 | 69 | [Support Universal Links](https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html) 70 | 71 | #### 配置 72 | 73 | ``` 74 | # 不需要做任何额外接入工作 75 | # 配置已集成到脚本里 76 | ``` 77 | 78 | * Universal Links 79 | 80 | apple-app-site-association - 通过 https://${your applinks domain}/.well-known/apple-app-site-association 链接可访问 81 | 82 | 示例: 83 | 84 | https://${your applinks domain}/universal_link/${example_app}/link_kit/ 85 | 86 | ```json 87 | { 88 | "applinks": { 89 | "apps": [], 90 | "details": [ 91 | { 92 | "appID": "${your team id}.${your app bundle id}", 93 | "paths": [ 94 | "/universal_link/${example_app}/link_kit/*" 95 | ] 96 | } 97 | ] 98 | } 99 | } 100 | ``` 101 | 102 | > ⚠️ 很多 SDK 都会用到 universal_link,可为不同 SDK 分配不同的 path 以作区分 103 | 104 | #### 测试 105 | 106 | ```shell 107 | # Deep Link 108 | xcrun simctl openurl booted flk:///power 109 | ``` 110 | 111 | ```shell 112 | # Universal Links 113 | xcrun simctl openurl booted https://www.yourdomain.com/universal_link/example_app/link_kit/power 114 | ``` 115 | 116 | ## Flutter 117 | 118 | #### 配置 119 | 120 | ```yaml 121 | dependencies: 122 | link_kit: ^${latestTag} 123 | # link_kit: 124 | # git: 125 | # url: https://github.com/RxReader/link_kit.git 126 | 127 | link_kit: 128 | deep_link: ${your deep link scheme}:/// 129 | android: 130 | app_link: https://${your applinks domain}/universal_link/${example_app}/link_kit/ # 可选配置 131 | ios: 132 | universal_link: https://${your applinks domain}/universal_link/${example_app}/link_kit/ # 可选配置 133 | ``` 134 | 135 | #### 安装 136 | 137 | ```shell 138 | # Android 139 | # 修改配置后,必须执行 flutter clean 清理中间编译产物 BuildConfig.java 140 | # step.1 切换工作目录 141 | cd example/ 142 | # step.2 143 | flutter clean && flutter pub get 144 | ``` 145 | 146 | ```shell 147 | # iOS 148 | # 首次/修改配置后,必须执行 pod install 让配置生效 149 | # step.0 安装必要依赖 150 | sudo gem install plist 151 | # step.1 切换工作目录 152 | cd example/ 153 | # step.2 154 | flutter clean && flutter pub get 155 | # step.3 执行脚本 156 | cd ios/ 157 | pod install 158 | ``` 159 | 160 | #### 编码 161 | 162 | ```dart 163 | _linkClickSubs = LinkKitPlatform.instance.linkClickStream().listen((String event) { 164 | if (kDebugMode) { 165 | print('linkClick: $event'); 166 | } 167 | setState(() { 168 | _link = event; 169 | }); 170 | }); 171 | LinkKitPlatform.instance.getInitialLink().then((String? value) { 172 | if (kDebugMode) { 173 | print('initialLink: $value'); 174 | } 175 | setState(() { 176 | _link = value; 177 | }); 178 | }); 179 | ``` 180 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Specify analysis options. 2 | # 3 | # Until there are meta linter rules, each desired lint must be explicitly enabled. 4 | # See: https://github.com/dart-lang/linter/issues/288 5 | # 6 | # For a list of lints, see: http://dart-lang.github.io/linter/lints/ 7 | # See the configuration guide for more 8 | # https://github.com/dart-lang/sdk/tree/main/pkg/analyzer#configuring-the-analyzer 9 | # 10 | # There are other similar analysis options files in the flutter repos, 11 | # which should be kept in sync with this file: 12 | # 13 | # - analysis_options.yaml (this file) 14 | # - https://github.com/flutter/plugins/blob/master/analysis_options.yaml 15 | # - https://github.com/flutter/engine/blob/master/analysis_options.yaml 16 | # - https://github.com/flutter/packages/blob/master/analysis_options.yaml 17 | # 18 | # This file contains the analysis options used by Flutter tools, such as IntelliJ, 19 | # Android Studio, and the `flutter analyze` command. 20 | 21 | analyzer: 22 | language: 23 | strict-raw-types: true 24 | errors: 25 | # treat missing required parameters as a warning (not a hint) 26 | missing_required_param: warning 27 | # treat missing returns as a warning (not a hint) 28 | missing_return: warning 29 | # allow having TODO comments in the code 30 | todo: ignore 31 | # allow self-reference to deprecated members (we do this because otherwise we have 32 | # to annotate every member in every test, assert, etc, when we deprecate something) 33 | deprecated_member_use_from_same_package: ignore 34 | # TODO(ianh): https://github.com/flutter/flutter/issues/74381 35 | # Clean up existing unnecessary imports, and remove line to ignore. 36 | unnecessary_import: ignore 37 | # Turned off until null-safe rollout is complete. 38 | unnecessary_null_comparison: ignore 39 | exclude: 40 | - "bin/cache/**" 41 | # Ignore protoc generated files 42 | - "dev/conductor/lib/proto/*" 43 | # 44 | - "lib/*.g.dart" 45 | - "lib/**/*.g.dart" 46 | 47 | linter: 48 | rules: 49 | # these rules are documented on and in the same order as 50 | # the Dart Lint rules page to make maintenance easier 51 | # https://github.com/dart-lang/linter/blob/master/example/all.yaml 52 | - always_declare_return_types 53 | - always_put_control_body_on_new_line 54 | # - always_put_required_named_parameters_first # we prefer having parameters in the same order as fields https://github.com/flutter/flutter/issues/10219 55 | - always_require_non_null_named_parameters 56 | - always_specify_types 57 | - always_use_package_imports # we do this commonly 58 | - annotate_overrides 59 | # - avoid_annotating_with_dynamic # conflicts with always_specify_types 60 | - avoid_bool_literals_in_conditional_expressions 61 | # - avoid_catches_without_on_clauses # blocked on https://github.com/dart-lang/linter/issues/3023 62 | # - avoid_catching_errors # blocked on https://github.com/dart-lang/linter/issues/3023 63 | - avoid_classes_with_only_static_members 64 | - avoid_double_and_int_checks 65 | - avoid_dynamic_calls 66 | - avoid_empty_else 67 | - avoid_equals_and_hash_code_on_mutable_classes 68 | - avoid_escaping_inner_quotes 69 | - avoid_field_initializers_in_const_classes 70 | # - avoid_final_parameters # incompatible with prefer_final_parameters 71 | - avoid_function_literals_in_foreach_calls 72 | - avoid_implementing_value_types 73 | - avoid_init_to_null 74 | - avoid_js_rounded_ints 75 | # - avoid_multiple_declarations_per_line # seems to be a stylistic choice we don't subscribe to 76 | - avoid_null_checks_in_equality_operators 77 | # - avoid_positional_boolean_parameters # would have been nice to enable this but by now there's too many places that break it 78 | - avoid_print 79 | # - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356) 80 | # - avoid_redundant_argument_values 81 | - avoid_relative_lib_imports 82 | - avoid_renaming_method_parameters 83 | - avoid_return_types_on_setters 84 | # - avoid_returning_null # still violated by some pre-nnbd code that we haven't yet migrated 85 | - avoid_returning_null_for_future 86 | - avoid_returning_null_for_void 87 | # - avoid_returning_this # there are enough valid reasons to return `this` that this lint ends up with too many false positives 88 | - avoid_setters_without_getters 89 | - avoid_shadowing_type_parameters 90 | - avoid_single_cascade_in_expression_statements 91 | - avoid_slow_async_io 92 | - avoid_type_to_string 93 | - avoid_types_as_parameter_names 94 | # - avoid_types_on_closure_parameters # conflicts with always_specify_types 95 | - avoid_unnecessary_containers 96 | - avoid_unused_constructor_parameters 97 | - avoid_void_async 98 | # - avoid_web_libraries_in_flutter # we use web libraries in web-specific code, and our tests prevent us from using them elsewhere 99 | - await_only_futures 100 | - camel_case_extensions 101 | - camel_case_types 102 | - cancel_subscriptions 103 | # - cascade_invocations # doesn't match the typical style of this repo 104 | - cast_nullable_to_non_nullable 105 | # - close_sinks # not reliable enough 106 | # - comment_references # blocked on https://github.com/dart-lang/linter/issues/1142 107 | # - conditional_uri_does_not_exist # not yet tested 108 | # - constant_identifier_names # needs an opt-out https://github.com/dart-lang/linter/issues/204 109 | - control_flow_in_finally 110 | # - curly_braces_in_flow_control_structures # not required by flutter style 111 | - depend_on_referenced_packages 112 | - deprecated_consistency 113 | # - diagnostic_describe_all_properties # enabled only at the framework level (packages/flutter/lib) 114 | - directives_ordering 115 | # - do_not_use_environment # there are appropriate times to use the environment, especially in our tests and build logic 116 | - empty_catches 117 | - empty_constructor_bodies 118 | - empty_statements 119 | - eol_at_end_of_file 120 | - exhaustive_cases 121 | - file_names 122 | - flutter_style_todos 123 | - hash_and_equals 124 | - implementation_imports 125 | # - invariant_booleans # too many false positives: https://github.com/dart-lang/linter/issues/811 126 | - iterable_contains_unrelated_type 127 | # - join_return_with_assignment # not required by flutter style 128 | - leading_newlines_in_multiline_strings 129 | - library_names 130 | - library_prefixes 131 | - library_private_types_in_public_api 132 | # - lines_longer_than_80_chars # not required by flutter style 133 | - list_remove_unrelated_type 134 | # - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/linter/issues/453 135 | - missing_whitespace_between_adjacent_strings 136 | - no_adjacent_strings_in_list 137 | - no_default_cases 138 | - no_duplicate_case_values 139 | - no_leading_underscores_for_library_prefixes 140 | - no_leading_underscores_for_local_identifiers 141 | - no_logic_in_create_state 142 | # - no_runtimeType_toString # ok in tests; we enable this only in packages/ 143 | - non_constant_identifier_names 144 | - noop_primitive_operations 145 | - null_check_on_nullable_type_parameter 146 | - null_closures 147 | # - omit_local_variable_types # opposite of always_specify_types 148 | # - one_member_abstracts # too many false positives 149 | - only_throw_errors # this does get disabled in a few places where we have legacy code that uses strings et al 150 | - overridden_fields 151 | - package_api_docs 152 | - package_names 153 | - package_prefixed_library_names 154 | # - parameter_assignments # we do this commonly 155 | - prefer_adjacent_string_concatenation 156 | - prefer_asserts_in_initializer_lists 157 | # - prefer_asserts_with_message # not required by flutter style 158 | - prefer_collection_literals 159 | - prefer_conditional_assignment 160 | # - prefer_const_constructors 161 | - prefer_const_constructors_in_immutables 162 | - prefer_const_declarations 163 | # - prefer_const_literals_to_create_immutables 164 | # - prefer_constructors_over_static_methods # far too many false positives 165 | - prefer_contains 166 | # - prefer_double_quotes # opposite of prefer_single_quotes 167 | - prefer_equal_for_default_values 168 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 169 | - prefer_final_fields 170 | - prefer_final_in_for_each 171 | - prefer_final_locals 172 | # - prefer_final_parameters # we should enable this one day when it can be auto-fixed (https://github.com/dart-lang/linter/issues/3104), see also parameter_assignments 173 | - prefer_for_elements_to_map_fromIterable 174 | - prefer_foreach 175 | - prefer_function_declarations_over_variables 176 | - prefer_generic_function_type_aliases 177 | - prefer_if_elements_to_conditional_expressions 178 | - prefer_if_null_operators 179 | - prefer_initializing_formals 180 | - prefer_inlined_adds 181 | # - prefer_int_literals # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-double-literals-for-double-constants 182 | - prefer_interpolation_to_compose_strings 183 | - prefer_is_empty 184 | - prefer_is_not_empty 185 | - prefer_is_not_operator 186 | - prefer_iterable_whereType 187 | # - prefer_mixin # Has false positives, see https://github.com/dart-lang/linter/issues/3018 188 | # - prefer_null_aware_method_calls # "call()" is confusing to people new to the language since it's not documented anywhere 189 | - prefer_null_aware_operators 190 | # - prefer_relative_imports 191 | - prefer_single_quotes 192 | - prefer_spread_collections 193 | - prefer_typing_uninitialized_variables 194 | - prefer_void_to_null 195 | - provide_deprecation_message 196 | # - public_member_api_docs # enabled on a case-by-case basis; see e.g. packages/analysis_options.yaml 197 | - recursive_getters 198 | # - require_trailing_commas # blocked on https://github.com/dart-lang/sdk/issues/47441 199 | - secure_pubspec_urls 200 | - sized_box_for_whitespace 201 | # - sized_box_shrink_expand # not yet tested 202 | - slash_for_doc_comments 203 | - sort_child_properties_last 204 | - sort_constructors_first 205 | # - sort_pub_dependencies # prevents separating pinned transitive dependencies 206 | - sort_unnamed_constructors_first 207 | - test_types_in_equals 208 | - throw_in_finally 209 | - tighten_type_of_initializing_formals 210 | # - type_annotate_public_apis # subset of always_specify_types 211 | - type_init_formals 212 | # - unawaited_futures # too many false positives, especially with the way AnimationController works 213 | - unnecessary_await_in_return 214 | - unnecessary_brace_in_string_interps 215 | - unnecessary_const 216 | - unnecessary_constructor_name 217 | # - unnecessary_final # conflicts with prefer_final_locals 218 | - unnecessary_getters_setters 219 | # - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498 220 | - unnecessary_late 221 | - unnecessary_new 222 | - unnecessary_null_aware_assignments 223 | - unnecessary_null_checks 224 | - unnecessary_null_in_if_null_operators 225 | - unnecessary_nullable_for_final_variable_declarations 226 | - unnecessary_overrides 227 | - unnecessary_parenthesis 228 | # - unnecessary_raw_strings # what's "necessary" is a matter of opinion; consistency across strings can help readability more than this lint 229 | - unnecessary_statements 230 | - unnecessary_string_escapes 231 | - unnecessary_string_interpolations 232 | - unnecessary_this 233 | - unrelated_type_equality_checks 234 | - unsafe_html 235 | - use_build_context_synchronously 236 | # - use_decorated_box # not yet tested 237 | - use_full_hex_values_for_flutter_colors 238 | - use_function_type_syntax_for_parameters 239 | - use_if_null_to_convert_nulls_to_bools 240 | - use_is_even_rather_than_modulo 241 | - use_key_in_widget_constructors 242 | - use_late_for_private_fields_and_variables 243 | - use_named_constants 244 | - use_raw_strings 245 | - use_rethrow_when_possible 246 | - use_setters_to_change_properties 247 | # - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182 248 | - use_test_throws_matchers 249 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 250 | - valid_regexps 251 | - void_checks 252 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .cxx 10 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | File pubspec = new File(project.projectDir.parentFile, 'pubspec.yaml') 2 | String yaml = pubspec.text 3 | // Using \s*['|"]?([^\n|'|"]*)['|"]? to extract version number. 4 | java.util.regex.Matcher versionMatcher = java.util.regex.Pattern.compile("^version:\\s*['|\"]?([^\\n|'|\"]*)['|\"]?\$", java.util.regex.Pattern.MULTILINE).matcher(yaml) 5 | versionMatcher.find() 6 | String library_version = versionMatcher.group(1).replaceAll("\\+", "-") 7 | 8 | File flutter_project_dir = rootProject.projectDir.parentFile 9 | def cfg = new org.yaml.snakeyaml.Yaml().load(new File(flutter_project_dir, 'pubspec.yaml').text) 10 | def deep_link = cfg.link_kit?.deep_link?.with { URI.create(it) } 11 | def app_link = cfg.link_kit?.android?.app_link?.with { URI.create(it) } 12 | if (deep_link == null || deep_link.scheme.isEmpty()) { 13 | throw new IllegalArgumentException("link_kit deep link is invalid, add code in pubspec.yaml:\nlink_kit:" + 14 | "\n deep_link: \${your deep link scheme}:///" + 15 | "\n android:" + 16 | "\n app_link: https://\${your applinks domain}/universal_link/\${example_app}/link_kit/ # 可选配置" + 17 | "\n ios:" + 18 | "\n universal_link: universal_link: https://\${your applinks domain}/universal_link/\${example_app}/link_kit/ # 可选配置") 19 | } 20 | 21 | group 'io.github.v7lin.link_kit' 22 | version library_version 23 | 24 | buildscript { 25 | repositories { 26 | google() 27 | mavenCentral() 28 | } 29 | 30 | dependencies { 31 | classpath 'com.android.tools.build:gradle:7.1.2' 32 | classpath 'org.yaml:snakeyaml:1.17' 33 | } 34 | } 35 | 36 | rootProject.allprojects { 37 | repositories { 38 | google() 39 | mavenCentral() 40 | } 41 | } 42 | 43 | apply plugin: 'com.android.library' 44 | 45 | android { 46 | if (project.android.hasProperty("namespace")) { 47 | namespace 'io.github.v7lin.link_kit' 48 | } 49 | 50 | compileSdkVersion 31 51 | 52 | compileOptions { 53 | sourceCompatibility JavaVersion.VERSION_1_8 54 | targetCompatibility JavaVersion.VERSION_1_8 55 | } 56 | 57 | resourcePrefix 'link_kit' 58 | 59 | defaultConfig { 60 | minSdkVersion 16 61 | 62 | buildConfigField "String", "LINK_KIT_DEEP_LINK_SCHEME", "\"${deep_link.scheme}\"" 63 | buildConfigField "String", "LINK_KIT_APP_LINK", "\"${app_link ?: ''}\"" 64 | 65 | manifestPlaceholders += [ 66 | DEEP_LINK_SCHEME: deep_link.scheme, 67 | ] 68 | if (app_link != null) { 69 | manifestPlaceholders += [ 70 | APP_LINK_SCHEME: app_link.scheme, 71 | APP_LINK_HOST: app_link.host, 72 | APP_LINK_PATH: "${app_link.path}.*", 73 | ] 74 | } 75 | } 76 | 77 | if (app_link != null) { 78 | flavorDimensions 'vendor' 79 | 80 | productFlavors { 81 | vendor { 82 | dimension 'vendor' 83 | } 84 | } 85 | } 86 | 87 | buildFeatures { 88 | buildConfig true 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'link_kit' 2 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /android/src/main/java/io/github/v7lin/link_kit/LinkCallbackActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.v7lin.link_kit; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | 10 | public class LinkCallbackActivity extends Activity { 11 | private static final String KEY_LINK_CALLBACK = "link_callback"; 12 | private static final String KEY_LINK_EXTRA = "link_extra"; 13 | 14 | @Override 15 | protected void onCreate(@Nullable Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | handleIntent(getIntent()); 18 | } 19 | 20 | @Override 21 | protected void onNewIntent(Intent intent) { 22 | super.onNewIntent(intent); 23 | handleIntent(intent); 24 | } 25 | 26 | private void handleIntent(Intent intent) { 27 | final Intent launchIntent = getPackageManager().getLaunchIntentForPackage(getPackageName()); 28 | launchIntent.putExtra(KEY_LINK_CALLBACK, true); 29 | launchIntent.putExtra(KEY_LINK_EXTRA, intent); 30 | // launchIntent.setPackage(getPackageName()); 31 | launchIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 32 | startActivity(launchIntent); 33 | finish(); 34 | } 35 | 36 | public static Intent extraCallback(@NonNull Intent intent) { 37 | if (intent.getExtras() != null && intent.getBooleanExtra(KEY_LINK_CALLBACK, false)) { 38 | final Intent extra = intent.getParcelableExtra(KEY_LINK_EXTRA); 39 | return extra; 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /android/src/main/java/io/github/v7lin/link_kit/LinkKitPlugin.java: -------------------------------------------------------------------------------- 1 | package io.github.v7lin.link_kit; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.text.TextUtils; 8 | 9 | import androidx.annotation.NonNull; 10 | 11 | import java.util.Arrays; 12 | import java.util.concurrent.atomic.AtomicBoolean; 13 | 14 | import io.flutter.embedding.engine.plugins.FlutterPlugin; 15 | import io.flutter.embedding.engine.plugins.activity.ActivityAware; 16 | import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; 17 | import io.flutter.plugin.common.EventChannel; 18 | import io.flutter.plugin.common.MethodCall; 19 | import io.flutter.plugin.common.MethodChannel; 20 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler; 21 | import io.flutter.plugin.common.MethodChannel.Result; 22 | import io.flutter.plugin.common.PluginRegistry; 23 | 24 | /** 25 | * LinkKitPlugin 26 | */ 27 | public class LinkKitPlugin implements FlutterPlugin, ActivityAware, PluginRegistry.NewIntentListener, MethodCallHandler { 28 | /// The MethodChannel that will the communication between Flutter and native Android 29 | /// 30 | /// This local reference serves to register the plugin with the Flutter Engine and unregister it 31 | /// when the Flutter Engine is detached from the Activity 32 | private MethodChannel channel; 33 | private EventChannel linkClickEventChannel; 34 | private LinkClickEventHandler linkClickEventHandler; 35 | private Context applicationContext; 36 | private ActivityPluginBinding activityPluginBinding; 37 | private final AtomicBoolean handleInitialFlag = new AtomicBoolean(false); 38 | 39 | // --- FlutterPlugin 40 | 41 | @Override 42 | public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { 43 | channel = new MethodChannel(binding.getBinaryMessenger(), "v7lin.github.io/link_kit"); 44 | channel.setMethodCallHandler(this); 45 | linkClickEventChannel = new EventChannel(binding.getBinaryMessenger(), "v7lin.github.io/link_kit#click_event"); 46 | linkClickEventHandler = new LinkClickEventHandler(); 47 | linkClickEventChannel.setStreamHandler(linkClickEventHandler); 48 | applicationContext = binding.getApplicationContext(); 49 | } 50 | 51 | @Override 52 | public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) { 53 | channel.setMethodCallHandler(null); 54 | channel = null; 55 | linkClickEventChannel.setStreamHandler(null); 56 | linkClickEventChannel = null; 57 | linkClickEventHandler = null; 58 | applicationContext = null; 59 | } 60 | 61 | private static class LinkClickEventHandler implements EventChannel.StreamHandler { 62 | private EventChannel.EventSink events; 63 | 64 | @Override 65 | public void onListen(Object arguments, EventChannel.EventSink events) { 66 | if (this.events != null) { 67 | return; 68 | } 69 | this.events = events; 70 | } 71 | 72 | @Override 73 | public void onCancel(Object arguments) { 74 | if (this.events == null) { 75 | return; 76 | } 77 | this.events = null; 78 | } 79 | 80 | public boolean isActive() { 81 | return this.events != null; 82 | } 83 | 84 | public void addEvent(String event) { 85 | if (events != null) { 86 | events.success(event); 87 | } 88 | } 89 | } 90 | 91 | // --- ActivityAware 92 | 93 | @Override 94 | public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { 95 | activityPluginBinding = binding; 96 | activityPluginBinding.addOnNewIntentListener(this); 97 | } 98 | 99 | @Override 100 | public void onDetachedFromActivityForConfigChanges() { 101 | onDetachedFromActivity(); 102 | } 103 | 104 | @Override 105 | public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) { 106 | onAttachedToActivity(binding); 107 | } 108 | 109 | @Override 110 | public void onDetachedFromActivity() { 111 | activityPluginBinding.removeOnNewIntentListener(this); 112 | activityPluginBinding = null; 113 | } 114 | 115 | // --- NewIntentListener 116 | 117 | @Override 118 | public boolean onNewIntent(@NonNull Intent intent) { 119 | final Intent extra = LinkCallbackActivity.extraCallback(intent); 120 | if (extra != null) { 121 | if (isFLKIntent(extra)) { 122 | final String link = extra.getDataString(); 123 | if (linkClickEventHandler != null) { 124 | linkClickEventHandler.addEvent(link); 125 | } 126 | } 127 | return true; 128 | } 129 | return false; 130 | } 131 | 132 | // --- MethodCallHandler 133 | 134 | @Override 135 | public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { 136 | if ("getInitialLink".equals(call.method)) { 137 | if (handleInitialFlag.compareAndSet(false, true)) { 138 | String initialLink = null; 139 | final Activity activity = activityPluginBinding != null ? activityPluginBinding.getActivity() : null; 140 | if (activity != null) { 141 | final Intent extra = LinkCallbackActivity.extraCallback(activity.getIntent()); 142 | if (extra != null) { 143 | if (isFLKIntent(extra)){ 144 | initialLink = extra.getDataString(); 145 | } 146 | } 147 | } 148 | result.success(initialLink); 149 | } else { 150 | result.error("FAILED", null, null); 151 | } 152 | } else { 153 | result.notImplemented(); 154 | } 155 | } 156 | 157 | private boolean isFLKIntent(@NonNull Intent intent) { 158 | final Uri data = intent.getData(); 159 | if (data != null) { 160 | if (Arrays.asList(BuildConfig.LINK_KIT_DEEP_LINK_SCHEME).contains(data.getScheme())) { 161 | // deep link 162 | return true; 163 | } else if (!TextUtils.isEmpty(BuildConfig.LINK_KIT_APP_LINK) && data.toString().startsWith(BuildConfig.LINK_KIT_APP_LINK)) { 164 | // app link 165 | return true; 166 | } 167 | } 168 | return false; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /android/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | -------------------------------------------------------------------------------- /android/src/vendor/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # link_kit_example 2 | 3 | Demonstrates how to use the link_kit plugin. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) 13 | 14 | For help getting started with Flutter development, view the 15 | [online documentation](https://docs.flutter.dev/), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Take our settings from the repo's main analysis_options.yaml file, but include 2 | # an additional rule to validate that public members are documented. 3 | 4 | include: ../analysis_options.yaml 5 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion flutter.compileSdkVersion 30 | ndkVersion flutter.ndkVersion 31 | 32 | compileOptions { 33 | sourceCompatibility JavaVersion.VERSION_1_8 34 | targetCompatibility JavaVersion.VERSION_1_8 35 | } 36 | 37 | defaultConfig { 38 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 39 | applicationId "io.github.v7lin.link_kit_example" 40 | // You can update the following values to match your application needs. 41 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. 42 | minSdkVersion flutter.minSdkVersion 43 | targetSdkVersion flutter.targetSdkVersion 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | } 47 | 48 | buildTypes { 49 | release { 50 | // TODO: Add your own signing config for the release build. 51 | // Signing with the debug keys for now, so `flutter run --release` works. 52 | signingConfig signingConfigs.debug 53 | } 54 | } 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/io/github/v7lin/link_kit_example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package io.github.v7lin.link_kit_example; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.1.2' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '11.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 32 | end 33 | 34 | post_install do |installer| 35 | installer.pods_project.targets.each do |target| 36 | flutter_additional_ios_build_settings(target) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Flutter (1.0.0) 3 | - link_kit (1.0.1): 4 | - Flutter 5 | - link_kit/vendor (= 1.0.1) 6 | - link_kit/vendor (1.0.1): 7 | - Flutter 8 | 9 | DEPENDENCIES: 10 | - Flutter (from `Flutter`) 11 | - link_kit (from `.symlinks/plugins/link_kit/ios`) 12 | 13 | EXTERNAL SOURCES: 14 | Flutter: 15 | :path: Flutter 16 | link_kit: 17 | :path: ".symlinks/plugins/link_kit/ios" 18 | 19 | SPEC CHECKSUMS: 20 | Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 21 | link_kit: 6f006b97ad8680e4fdc2201094ecdd4a70fd972f 22 | 23 | PODFILE CHECKSUM: 663715e941f9adb426e33bf9376914006f9ea95b 24 | 25 | COCOAPODS: 1.12.1 26 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 13 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 14 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 15 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 16 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 17 | F4E4891774623A7A7ACD87F5 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B0EA18F8EB899CA824A66921 /* libPods-Runner.a */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = ""; 25 | dstSubfolderSpec = 10; 26 | files = ( 27 | ); 28 | name = "Embed Frameworks"; 29 | runOnlyForDeploymentPostprocessing = 0; 30 | }; 31 | /* End PBXCopyFilesBuildPhase section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 36 | 202555056C72260B24399B39 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 37 | 25B2AF1E4CF0AD4411516A5A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 38 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 39 | 47CFB47EC104F51C977B8D95 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 40 | 5FA3EEDB69D3726002807968 /* Runner.entitlements */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 41 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 42 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 45 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 46 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 49 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 50 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 52 | B0EA18F8EB899CA824A66921 /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | F4E4891774623A7A7ACD87F5 /* libPods-Runner.a in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | /* End PBXFrameworksBuildPhase section */ 65 | 66 | /* Begin PBXGroup section */ 67 | 5475207D52D16D100DD53D38 /* Pods */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | 25B2AF1E4CF0AD4411516A5A /* Pods-Runner.debug.xcconfig */, 71 | 202555056C72260B24399B39 /* Pods-Runner.release.xcconfig */, 72 | 47CFB47EC104F51C977B8D95 /* Pods-Runner.profile.xcconfig */, 73 | ); 74 | path = Pods; 75 | sourceTree = ""; 76 | }; 77 | 879099D8A5B180A27E913B9E /* Frameworks */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | B0EA18F8EB899CA824A66921 /* libPods-Runner.a */, 81 | ); 82 | name = Frameworks; 83 | sourceTree = ""; 84 | }; 85 | 9740EEB11CF90186004384FC /* Flutter */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 89 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 90 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 91 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 92 | ); 93 | name = Flutter; 94 | sourceTree = ""; 95 | }; 96 | 97C146E51CF9000F007C117D = { 97 | isa = PBXGroup; 98 | children = ( 99 | 9740EEB11CF90186004384FC /* Flutter */, 100 | 97C146F01CF9000F007C117D /* Runner */, 101 | 97C146EF1CF9000F007C117D /* Products */, 102 | 5475207D52D16D100DD53D38 /* Pods */, 103 | 879099D8A5B180A27E913B9E /* Frameworks */, 104 | ); 105 | sourceTree = ""; 106 | }; 107 | 97C146EF1CF9000F007C117D /* Products */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 97C146EE1CF9000F007C117D /* Runner.app */, 111 | ); 112 | name = Products; 113 | sourceTree = ""; 114 | }; 115 | 97C146F01CF9000F007C117D /* Runner */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 119 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 120 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 121 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 122 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 123 | 97C147021CF9000F007C117D /* Info.plist */, 124 | 97C146F11CF9000F007C117D /* Supporting Files */, 125 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 126 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 127 | 5FA3EEDB69D3726002807968 /* Runner.entitlements */, 128 | ); 129 | path = Runner; 130 | sourceTree = ""; 131 | }; 132 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 97C146F21CF9000F007C117D /* main.m */, 136 | ); 137 | name = "Supporting Files"; 138 | sourceTree = ""; 139 | }; 140 | /* End PBXGroup section */ 141 | 142 | /* Begin PBXNativeTarget section */ 143 | 97C146ED1CF9000F007C117D /* Runner */ = { 144 | isa = PBXNativeTarget; 145 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 146 | buildPhases = ( 147 | 6476505D1D8AA350B847087E /* [CP] Check Pods Manifest.lock */, 148 | 9740EEB61CF901F6004384FC /* Run Script */, 149 | 97C146EA1CF9000F007C117D /* Sources */, 150 | 97C146EB1CF9000F007C117D /* Frameworks */, 151 | 97C146EC1CF9000F007C117D /* Resources */, 152 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 153 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 154 | ); 155 | buildRules = ( 156 | ); 157 | dependencies = ( 158 | ); 159 | name = Runner; 160 | productName = Runner; 161 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | /* End PBXNativeTarget section */ 165 | 166 | /* Begin PBXProject section */ 167 | 97C146E61CF9000F007C117D /* Project object */ = { 168 | isa = PBXProject; 169 | attributes = { 170 | LastUpgradeCheck = 1300; 171 | ORGANIZATIONNAME = ""; 172 | TargetAttributes = { 173 | 97C146ED1CF9000F007C117D = { 174 | CreatedOnToolsVersion = 7.3.1; 175 | }; 176 | }; 177 | }; 178 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 179 | compatibilityVersion = "Xcode 9.3"; 180 | developmentRegion = en; 181 | hasScannedForEncodings = 0; 182 | knownRegions = ( 183 | en, 184 | Base, 185 | ); 186 | mainGroup = 97C146E51CF9000F007C117D; 187 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 188 | projectDirPath = ""; 189 | projectRoot = ""; 190 | targets = ( 191 | 97C146ED1CF9000F007C117D /* Runner */, 192 | ); 193 | }; 194 | /* End PBXProject section */ 195 | 196 | /* Begin PBXResourcesBuildPhase section */ 197 | 97C146EC1CF9000F007C117D /* Resources */ = { 198 | isa = PBXResourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 202 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 203 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 204 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXResourcesBuildPhase section */ 209 | 210 | /* Begin PBXShellScriptBuildPhase section */ 211 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 212 | isa = PBXShellScriptBuildPhase; 213 | alwaysOutOfDate = 1; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | ); 217 | inputPaths = ( 218 | ); 219 | name = "Thin Binary"; 220 | outputPaths = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | shellPath = /bin/sh; 224 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 225 | }; 226 | 6476505D1D8AA350B847087E /* [CP] Check Pods Manifest.lock */ = { 227 | isa = PBXShellScriptBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | inputFileListPaths = ( 232 | ); 233 | inputPaths = ( 234 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 235 | "${PODS_ROOT}/Manifest.lock", 236 | ); 237 | name = "[CP] Check Pods Manifest.lock"; 238 | outputFileListPaths = ( 239 | ); 240 | outputPaths = ( 241 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | shellPath = /bin/sh; 245 | 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"; 246 | showEnvVarsInLog = 0; 247 | }; 248 | 9740EEB61CF901F6004384FC /* Run Script */ = { 249 | isa = PBXShellScriptBuildPhase; 250 | alwaysOutOfDate = 1; 251 | buildActionMask = 2147483647; 252 | files = ( 253 | ); 254 | inputPaths = ( 255 | ); 256 | name = "Run Script"; 257 | outputPaths = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | shellPath = /bin/sh; 261 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 262 | }; 263 | /* End PBXShellScriptBuildPhase section */ 264 | 265 | /* Begin PBXSourcesBuildPhase section */ 266 | 97C146EA1CF9000F007C117D /* Sources */ = { 267 | isa = PBXSourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 271 | 97C146F31CF9000F007C117D /* main.m in Sources */, 272 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXVariantGroup section */ 279 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 280 | isa = PBXVariantGroup; 281 | children = ( 282 | 97C146FB1CF9000F007C117D /* Base */, 283 | ); 284 | name = Main.storyboard; 285 | sourceTree = ""; 286 | }; 287 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | 97C147001CF9000F007C117D /* Base */, 291 | ); 292 | name = LaunchScreen.storyboard; 293 | sourceTree = ""; 294 | }; 295 | /* End PBXVariantGroup section */ 296 | 297 | /* Begin XCBuildConfiguration section */ 298 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_ANALYZER_NONNULL = YES; 303 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 304 | CLANG_CXX_LIBRARY = "libc++"; 305 | CLANG_ENABLE_MODULES = YES; 306 | CLANG_ENABLE_OBJC_ARC = YES; 307 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 308 | CLANG_WARN_BOOL_CONVERSION = YES; 309 | CLANG_WARN_COMMA = YES; 310 | CLANG_WARN_CONSTANT_CONVERSION = YES; 311 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 312 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INFINITE_RECURSION = YES; 316 | CLANG_WARN_INT_CONVERSION = YES; 317 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 318 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 319 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 322 | CLANG_WARN_STRICT_PROTOTYPES = YES; 323 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 324 | CLANG_WARN_UNREACHABLE_CODE = YES; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 327 | COPY_PHASE_STRIP = NO; 328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 329 | ENABLE_NS_ASSERTIONS = NO; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | GCC_C_LANGUAGE_STANDARD = gnu99; 332 | GCC_NO_COMMON_BLOCKS = YES; 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 340 | MTL_ENABLE_DEBUG_INFO = NO; 341 | SDKROOT = iphoneos; 342 | SUPPORTED_PLATFORMS = iphoneos; 343 | TARGETED_DEVICE_FAMILY = "1,2"; 344 | VALIDATE_PRODUCT = YES; 345 | }; 346 | name = Profile; 347 | }; 348 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 349 | isa = XCBuildConfiguration; 350 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 351 | buildSettings = { 352 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 353 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 354 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 355 | DEVELOPMENT_TEAM = 78W43A3TE2; 356 | ENABLE_BITCODE = NO; 357 | INFOPLIST_FILE = Runner/Info.plist; 358 | LD_RUNPATH_SEARCH_PATHS = ( 359 | "$(inherited)", 360 | "@executable_path/Frameworks", 361 | ); 362 | PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.linkKitExample; 363 | PRODUCT_NAME = "$(TARGET_NAME)"; 364 | VERSIONING_SYSTEM = "apple-generic"; 365 | }; 366 | name = Profile; 367 | }; 368 | 97C147031CF9000F007C117D /* Debug */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_ANALYZER_NONNULL = YES; 373 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 374 | CLANG_CXX_LIBRARY = "libc++"; 375 | CLANG_ENABLE_MODULES = YES; 376 | CLANG_ENABLE_OBJC_ARC = YES; 377 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 378 | CLANG_WARN_BOOL_CONVERSION = YES; 379 | CLANG_WARN_COMMA = YES; 380 | CLANG_WARN_CONSTANT_CONVERSION = YES; 381 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 382 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 383 | CLANG_WARN_EMPTY_BODY = YES; 384 | CLANG_WARN_ENUM_CONVERSION = YES; 385 | CLANG_WARN_INFINITE_RECURSION = YES; 386 | CLANG_WARN_INT_CONVERSION = YES; 387 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 388 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 389 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 390 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 391 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 392 | CLANG_WARN_STRICT_PROTOTYPES = YES; 393 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 394 | CLANG_WARN_UNREACHABLE_CODE = YES; 395 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 396 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 397 | COPY_PHASE_STRIP = NO; 398 | DEBUG_INFORMATION_FORMAT = dwarf; 399 | ENABLE_STRICT_OBJC_MSGSEND = YES; 400 | ENABLE_TESTABILITY = YES; 401 | GCC_C_LANGUAGE_STANDARD = gnu99; 402 | GCC_DYNAMIC_NO_PIC = NO; 403 | GCC_NO_COMMON_BLOCKS = YES; 404 | GCC_OPTIMIZATION_LEVEL = 0; 405 | GCC_PREPROCESSOR_DEFINITIONS = ( 406 | "DEBUG=1", 407 | "$(inherited)", 408 | ); 409 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 410 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 411 | GCC_WARN_UNDECLARED_SELECTOR = YES; 412 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 413 | GCC_WARN_UNUSED_FUNCTION = YES; 414 | GCC_WARN_UNUSED_VARIABLE = YES; 415 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 416 | MTL_ENABLE_DEBUG_INFO = YES; 417 | ONLY_ACTIVE_ARCH = YES; 418 | SDKROOT = iphoneos; 419 | TARGETED_DEVICE_FAMILY = "1,2"; 420 | }; 421 | name = Debug; 422 | }; 423 | 97C147041CF9000F007C117D /* Release */ = { 424 | isa = XCBuildConfiguration; 425 | buildSettings = { 426 | ALWAYS_SEARCH_USER_PATHS = NO; 427 | CLANG_ANALYZER_NONNULL = YES; 428 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 429 | CLANG_CXX_LIBRARY = "libc++"; 430 | CLANG_ENABLE_MODULES = YES; 431 | CLANG_ENABLE_OBJC_ARC = YES; 432 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 433 | CLANG_WARN_BOOL_CONVERSION = YES; 434 | CLANG_WARN_COMMA = YES; 435 | CLANG_WARN_CONSTANT_CONVERSION = YES; 436 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 437 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 443 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 444 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 446 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 447 | CLANG_WARN_STRICT_PROTOTYPES = YES; 448 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 449 | CLANG_WARN_UNREACHABLE_CODE = YES; 450 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 451 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 452 | COPY_PHASE_STRIP = NO; 453 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 454 | ENABLE_NS_ASSERTIONS = NO; 455 | ENABLE_STRICT_OBJC_MSGSEND = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu99; 457 | GCC_NO_COMMON_BLOCKS = YES; 458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 459 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 460 | GCC_WARN_UNDECLARED_SELECTOR = YES; 461 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 462 | GCC_WARN_UNUSED_FUNCTION = YES; 463 | GCC_WARN_UNUSED_VARIABLE = YES; 464 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 465 | MTL_ENABLE_DEBUG_INFO = NO; 466 | SDKROOT = iphoneos; 467 | SUPPORTED_PLATFORMS = iphoneos; 468 | TARGETED_DEVICE_FAMILY = "1,2"; 469 | VALIDATE_PRODUCT = YES; 470 | }; 471 | name = Release; 472 | }; 473 | 97C147061CF9000F007C117D /* Debug */ = { 474 | isa = XCBuildConfiguration; 475 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 476 | buildSettings = { 477 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 478 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 479 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 480 | DEVELOPMENT_TEAM = 78W43A3TE2; 481 | ENABLE_BITCODE = NO; 482 | INFOPLIST_FILE = Runner/Info.plist; 483 | LD_RUNPATH_SEARCH_PATHS = ( 484 | "$(inherited)", 485 | "@executable_path/Frameworks", 486 | ); 487 | PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.linkKitExample; 488 | PRODUCT_NAME = "$(TARGET_NAME)"; 489 | VERSIONING_SYSTEM = "apple-generic"; 490 | }; 491 | name = Debug; 492 | }; 493 | 97C147071CF9000F007C117D /* Release */ = { 494 | isa = XCBuildConfiguration; 495 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 496 | buildSettings = { 497 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 498 | CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; 499 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 500 | DEVELOPMENT_TEAM = 78W43A3TE2; 501 | ENABLE_BITCODE = NO; 502 | INFOPLIST_FILE = Runner/Info.plist; 503 | LD_RUNPATH_SEARCH_PATHS = ( 504 | "$(inherited)", 505 | "@executable_path/Frameworks", 506 | ); 507 | PRODUCT_BUNDLE_IDENTIFIER = io.github.v7lin.linkKitExample; 508 | PRODUCT_NAME = "$(TARGET_NAME)"; 509 | VERSIONING_SYSTEM = "apple-generic"; 510 | }; 511 | name = Release; 512 | }; 513 | /* End XCBuildConfiguration section */ 514 | 515 | /* Begin XCConfigurationList section */ 516 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | 97C147031CF9000F007C117D /* Debug */, 520 | 97C147041CF9000F007C117D /* Release */, 521 | 249021D3217E4FDB00AE95B9 /* Profile */, 522 | ); 523 | defaultConfigurationIsVisible = 0; 524 | defaultConfigurationName = Release; 525 | }; 526 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 527 | isa = XCConfigurationList; 528 | buildConfigurations = ( 529 | 97C147061CF9000F007C117D /* Debug */, 530 | 97C147071CF9000F007C117D /* Release */, 531 | 249021D4217E4FDB00AE95B9 /* Profile */, 532 | ); 533 | defaultConfigurationIsVisible = 0; 534 | defaultConfigurationName = Release; 535 | }; 536 | /* End XCConfigurationList section */ 537 | }; 538 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 539 | } 540 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CADisableMinimumFrameDurationOnPhone 6 | 7 | CFBundleDevelopmentRegion 8 | $(DEVELOPMENT_LANGUAGE) 9 | CFBundleDisplayName 10 | Link Kit 11 | CFBundleExecutable 12 | $(EXECUTABLE_NAME) 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | link_kit_example 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleSignature 24 | ???? 25 | CFBundleURLTypes 26 | 27 | 28 | CFBundleTypeRole 29 | Editor 30 | CFBundleURLName 31 | link 32 | CFBundleURLSchemes 33 | 34 | flk 35 | 36 | 37 | 38 | CFBundleVersion 39 | $(FLUTTER_BUILD_NUMBER) 40 | LSRequiresIPhoneOS 41 | 42 | UIApplicationSupportsIndirectInputEvents 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | UIViewControllerBasedStatusBarAppearance 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.associated-domains 6 | 7 | applinks:www.yourdomain.com 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:link_kit/link_kit.dart'; 6 | 7 | void main() { 8 | runApp(MyApp()); 9 | } 10 | 11 | class MyApp extends StatefulWidget { 12 | const MyApp({ 13 | super.key, 14 | }); 15 | 16 | @override 17 | State createState() => _MyAppState(); 18 | } 19 | 20 | class _MyAppState extends State { 21 | String? _link; 22 | StreamSubscription? _linkClickSubs; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | _linkClickSubs = 28 | LinkKitPlatform.instance.linkClickStream().listen((String event) { 29 | if (kDebugMode) { 30 | print('linkClick: $event'); 31 | } 32 | setState(() { 33 | _link = event; 34 | }); 35 | }); 36 | // ⚠️⚠️⚠️ 37 | // 因为 Android 层实现调用了 queryIntentActivities,会被(小米)误判【获取安装列表】 38 | // 所以 getInitialLink 必须在同意「隐私协议」后才能调用 39 | LinkKitPlatform.instance.getInitialLink().then((String? value) { 40 | if (kDebugMode) { 41 | print('initialLink: $value'); 42 | } 43 | setState(() { 44 | _link = value; 45 | }); 46 | }); 47 | } 48 | 49 | @override 50 | void dispose() { 51 | _linkClickSubs?.cancel(); 52 | super.dispose(); 53 | } 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return MaterialApp( 58 | home: Scaffold( 59 | appBar: AppBar( 60 | title: Text('Link Kit'), 61 | ), 62 | body: Center( 63 | child: Text(_link ?? ''), 64 | ), 65 | ), 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 9 | url: "https://pub.flutter-io.cn" 10 | source: hosted 11 | version: "2.10.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.flutter-io.cn" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 25 | url: "https://pub.flutter-io.cn" 26 | source: hosted 27 | version: "1.2.1" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.flutter-io.cn" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 41 | url: "https://pub.flutter-io.cn" 42 | source: hosted 43 | version: "1.17.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be 49 | url: "https://pub.flutter-io.cn" 50 | source: hosted 51 | version: "1.0.5" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.flutter-io.cn" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c 70 | url: "https://pub.flutter-io.cn" 71 | source: hosted 72 | version: "2.0.1" 73 | flutter_test: 74 | dependency: "direct dev" 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | js: 79 | dependency: transitive 80 | description: 81 | name: js 82 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 83 | url: "https://pub.flutter-io.cn" 84 | source: hosted 85 | version: "0.6.5" 86 | link_kit: 87 | dependency: "direct main" 88 | description: 89 | path: ".." 90 | relative: true 91 | source: path 92 | version: "1.0.1" 93 | lints: 94 | dependency: transitive 95 | description: 96 | name: lints 97 | sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" 98 | url: "https://pub.flutter-io.cn" 99 | source: hosted 100 | version: "2.0.0" 101 | matcher: 102 | dependency: transitive 103 | description: 104 | name: matcher 105 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 106 | url: "https://pub.flutter-io.cn" 107 | source: hosted 108 | version: "0.12.13" 109 | material_color_utilities: 110 | dependency: transitive 111 | description: 112 | name: material_color_utilities 113 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 114 | url: "https://pub.flutter-io.cn" 115 | source: hosted 116 | version: "0.2.0" 117 | meta: 118 | dependency: transitive 119 | description: 120 | name: meta 121 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 122 | url: "https://pub.flutter-io.cn" 123 | source: hosted 124 | version: "1.8.0" 125 | path: 126 | dependency: transitive 127 | description: 128 | name: path 129 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 130 | url: "https://pub.flutter-io.cn" 131 | source: hosted 132 | version: "1.8.2" 133 | plugin_platform_interface: 134 | dependency: transitive 135 | description: 136 | name: plugin_platform_interface 137 | sha256: "075f927ebbab4262ace8d0b283929ac5410c0ac4e7fc123c76429564facfb757" 138 | url: "https://pub.flutter-io.cn" 139 | source: hosted 140 | version: "2.1.2" 141 | sky_engine: 142 | dependency: transitive 143 | description: flutter 144 | source: sdk 145 | version: "0.0.99" 146 | source_span: 147 | dependency: transitive 148 | description: 149 | name: source_span 150 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 151 | url: "https://pub.flutter-io.cn" 152 | source: hosted 153 | version: "1.9.1" 154 | stack_trace: 155 | dependency: transitive 156 | description: 157 | name: stack_trace 158 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 159 | url: "https://pub.flutter-io.cn" 160 | source: hosted 161 | version: "1.11.0" 162 | stream_channel: 163 | dependency: transitive 164 | description: 165 | name: stream_channel 166 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 167 | url: "https://pub.flutter-io.cn" 168 | source: hosted 169 | version: "2.1.1" 170 | string_scanner: 171 | dependency: transitive 172 | description: 173 | name: string_scanner 174 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 175 | url: "https://pub.flutter-io.cn" 176 | source: hosted 177 | version: "1.2.0" 178 | term_glyph: 179 | dependency: transitive 180 | description: 181 | name: term_glyph 182 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 183 | url: "https://pub.flutter-io.cn" 184 | source: hosted 185 | version: "1.2.1" 186 | test_api: 187 | dependency: transitive 188 | description: 189 | name: test_api 190 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 191 | url: "https://pub.flutter-io.cn" 192 | source: hosted 193 | version: "0.4.16" 194 | vector_math: 195 | dependency: transitive 196 | description: 197 | name: vector_math 198 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 199 | url: "https://pub.flutter-io.cn" 200 | source: hosted 201 | version: "2.1.4" 202 | sdks: 203 | dart: ">=2.18.0 <3.0.0" 204 | flutter: ">=2.5.0" 205 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: link_kit_example 2 | description: Demonstrates how to use the link_kit plugin. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 7 | 8 | environment: 9 | sdk: ">=2.17.6 <3.0.0" 10 | 11 | # Dependencies specify other packages that your package needs in order to work. 12 | # To automatically upgrade your package dependencies to the latest versions 13 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 14 | # dependencies can be manually updated by changing the version numbers below to 15 | # the latest version available on pub.dev. To see which dependencies have newer 16 | # versions available, run `flutter pub outdated`. 17 | dependencies: 18 | flutter: 19 | sdk: flutter 20 | 21 | link_kit: 22 | # When depending on this package from a real application you should use: 23 | # link_kit: ^x.y.z 24 | # See https://dart.dev/tools/pub/dependencies#version-constraints 25 | # The example app is bundled with the plugin so we use a path dependency on 26 | # the parent directory to use the current plugin's version. 27 | path: ../ 28 | 29 | # The following adds the Cupertino Icons font to your application. 30 | # Use with the CupertinoIcons class for iOS style icons. 31 | cupertino_icons: ^1.0.2 32 | 33 | dev_dependencies: 34 | flutter_test: 35 | sdk: flutter 36 | 37 | # The "flutter_lints" package below contains a set of recommended lints to 38 | # encourage good coding practices. The lint set provided by the package is 39 | # activated in the `analysis_options.yaml` file located at the root of your 40 | # package. See that file for information about deactivating specific lint 41 | # rules and activating additional ones. 42 | flutter_lints: ^2.0.0 43 | 44 | # For information on the generic Dart part of this file, see the 45 | # following page: https://dart.dev/tools/pub/pubspec 46 | 47 | # The following section is specific to Flutter packages. 48 | flutter: 49 | 50 | # The following line ensures that the Material Icons font is 51 | # included with your application, so that you can use the icons in 52 | # the material Icons class. 53 | uses-material-design: true 54 | 55 | # To add assets to your application, add an assets section, like this: 56 | # assets: 57 | # - images/a_dot_burr.jpeg 58 | # - images/a_dot_ham.jpeg 59 | 60 | # An image asset can refer to one or more resolution-specific "variants", see 61 | # https://flutter.dev/assets-and-images/#resolution-aware 62 | 63 | # For details regarding adding assets from package dependencies, see 64 | # https://flutter.dev/assets-and-images/#from-packages 65 | 66 | # To add custom fonts to your application, add a fonts section here, 67 | # in this "flutter" section. Each entry in this list should have a 68 | # "family" key with the font family name, and a "fonts" key with a 69 | # list giving the asset and other descriptors for the font. For 70 | # example: 71 | # fonts: 72 | # - family: Schyler 73 | # fonts: 74 | # - asset: fonts/Schyler-Regular.ttf 75 | # - asset: fonts/Schyler-Italic.ttf 76 | # style: italic 77 | # - family: Trajan Pro 78 | # fonts: 79 | # - asset: fonts/TrajanPro.ttf 80 | # - asset: fonts/TrajanPro_Bold.ttf 81 | # weight: 700 82 | # 83 | # For details regarding fonts from package dependencies, 84 | # see https://flutter.dev/custom-fonts/#from-packages 85 | 86 | link_kit: 87 | deep_link: flk:/// 88 | android: 89 | app_link: https://www.yourdomain.com/universal_link/example_app/link_kit/ # 可选配置 90 | ios: 91 | universal_link: https://www.yourdomain.com/universal_link/example_app/link_kit/ # 可选配置 92 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility in the flutter_test package. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:link_kit_example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Verify Platform version', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that platform version is retrieved. 19 | expect( 20 | find.byWidgetPredicate( 21 | (Widget widget) => 22 | widget is Text && widget.data!.startsWith('Running on:'), 23 | ), 24 | findsOneWidget, 25 | ); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /ios/.clang-format: -------------------------------------------------------------------------------- 1 | # 基础样式 2 | BasedOnStyle: LLVM 3 | 4 | # 缩进宽度 5 | IndentWidth: 4 6 | 7 | # 圆括号的换行方式 8 | BreakBeforeBraces: Attach 9 | 10 | # 是否允许循环单行 11 | AllowShortLoopsOnASingleLine: false 12 | 13 | # 支持一行的if 14 | AllowShortIfStatementsOnASingleLine: false 15 | 16 | # switch的case缩进 17 | IndentCaseLabels: true 18 | 19 | # 针对OC的block的缩进宽度 20 | ObjCBlockIndentWidth: 4 21 | 22 | # 针对OC,属性名后加空格 23 | ObjCSpaceAfterProperty: true 24 | 25 | # 每行字符的长度 26 | ColumnLimit: 0 27 | 28 | # 注释对齐 29 | AlignTrailingComments: true 30 | 31 | # 括号后加空格 32 | SpaceAfterCStyleCast: false 33 | 34 | # 不在小括号里加空格 35 | SpacesInParentheses: false 36 | 37 | # 不在中括号里加空格 38 | SpacesInSquareBrackets: false 39 | 40 | AllowShortBlocksOnASingleLine: false 41 | 42 | AllowShortCaseLabelsOnASingleLine: false 43 | 44 | AllowShortFunctionsOnASingleLine: false 45 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/Generated.xcconfig 37 | /Flutter/ephemeral/ 38 | /Flutter/flutter_export_environment.sh -------------------------------------------------------------------------------- /ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RxReader/link_kit/32e53e81f88c92b2be9f68c346c5bca190191f47/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /ios/Classes/LinkKitPlugin.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface LinkKitPlugin : NSObject 4 | @end 5 | 6 | @interface LinkKitLinkClickEventHandler : NSObject 7 | 8 | - (void)addEvent:(NSString *)event; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /ios/Classes/LinkKitPlugin.m: -------------------------------------------------------------------------------- 1 | #import "LinkKitPlugin.h" 2 | 3 | @implementation LinkKitPlugin { 4 | BOOL _isRunning; 5 | BOOL _handleInitialFlag; 6 | LinkKitLinkClickEventHandler *_linkClickEventHandler; 7 | NSString *_initialLink; 8 | } 9 | 10 | + (void)registerWithRegistrar:(NSObject *)registrar { 11 | FlutterEventChannel *linkClickEventChannel = [FlutterEventChannel eventChannelWithName:@"v7lin.github.io/link_kit#click_event" binaryMessenger:[registrar messenger]]; 12 | LinkKitLinkClickEventHandler *linkClickEventHandler = [[LinkKitLinkClickEventHandler alloc] init]; 13 | [linkClickEventChannel setStreamHandler:linkClickEventHandler]; 14 | FlutterMethodChannel *channel = [FlutterMethodChannel 15 | methodChannelWithName:@"v7lin.github.io/link_kit" 16 | binaryMessenger:[registrar messenger]]; 17 | LinkKitPlugin *instance = [[LinkKitPlugin alloc] initWithLinkClickEventHandler:linkClickEventHandler]; 18 | [registrar addApplicationDelegate:instance]; 19 | [registrar addMethodCallDelegate:instance channel:channel]; 20 | } 21 | 22 | - (instancetype)initWithLinkClickEventHandler:(LinkKitLinkClickEventHandler *)linkClickEventHandler { 23 | self = [super init]; 24 | if (self) { 25 | _isRunning = NO; 26 | _handleInitialFlag = NO; 27 | _linkClickEventHandler = linkClickEventHandler; 28 | _initialLink = nil; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result { 34 | if ([@"getInitialLink" isEqualToString:call.method]) { 35 | if (!_handleInitialFlag) { 36 | _handleInitialFlag = YES; 37 | _isRunning = YES; 38 | result(_initialLink); 39 | } else { 40 | result([FlutterError errorWithCode:@"FAILED" message:nil details:nil]); 41 | } 42 | } else { 43 | result(FlutterMethodNotImplemented); 44 | } 45 | } 46 | 47 | - (BOOL)isFLKDeepLink:(NSURL *)url { 48 | NSArray *schemes = @[ LINK_KIT_DEEP_LINK_SCHEME ]; 49 | for (NSString *scheme in schemes) { 50 | if ([scheme isEqualToString:url.scheme]) { 51 | return YES; 52 | } 53 | } 54 | return NO; 55 | } 56 | 57 | #pragma mark - AppDelegate 58 | 59 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 60 | NSURL *url = (NSURL *)launchOptions[UIApplicationLaunchOptionsURLKey]; 61 | if (url != nil && url != NULL && ![url isEqual:[NSNull null]]) { 62 | if ([self isFLKDeepLink:url]) { 63 | _initialLink = url.absoluteString; 64 | return YES; 65 | } 66 | } 67 | return NO; 68 | } 69 | 70 | - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url { 71 | return [self handleDeepLinkClickEvent:url]; 72 | } 73 | 74 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { 75 | return [self handleDeepLinkClickEvent:url]; 76 | } 77 | 78 | - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { 79 | return [self handleDeepLinkClickEvent:url]; 80 | } 81 | 82 | - (BOOL)handleDeepLinkClickEvent:(NSURL *)url { 83 | if (url != nil && url != NULL && ![url isEqual:[NSNull null]]) { 84 | if ([self isFLKDeepLink:url]) { 85 | if (_linkClickEventHandler != nil) { 86 | [_linkClickEventHandler addEvent:url.absoluteString]; 87 | } 88 | return YES; 89 | } 90 | } 91 | return NO; 92 | } 93 | 94 | #ifdef LINK_KIT_UNIVERSAL_LINK 95 | 96 | - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *_Nonnull))restorationHandler { 97 | return [self handleUniversalLinkClickEvent:application continueUserActivity:userActivity restorationHandler:restorationHandler]; 98 | } 99 | 100 | - (BOOL)handleUniversalLinkClickEvent:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *_Nonnull))restorationHandler { 101 | if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) { 102 | NSURL *url = userActivity.webpageURL; 103 | if ([self isFLKUniversalLink:url]) { 104 | if (!_isRunning) { 105 | _initialLink = url.absoluteString; 106 | } else { 107 | if (_linkClickEventHandler != nil) { 108 | [_linkClickEventHandler addEvent:url.absoluteString]; 109 | } 110 | } 111 | return YES; 112 | } 113 | } 114 | return NO; 115 | } 116 | 117 | - (BOOL)isFLKUniversalLink:(NSURL *)url { 118 | NSURL *universalLink = [NSURL URLWithString:LINK_KIT_UNIVERSAL_LINK]; 119 | if ([url.absoluteString hasPrefix:universalLink.absoluteString]) { 120 | return YES; 121 | } 122 | return NO; 123 | } 124 | 125 | #endif 126 | 127 | @end 128 | 129 | @implementation LinkKitLinkClickEventHandler { 130 | FlutterEventSink _events; 131 | } 132 | 133 | - (FlutterError *_Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events { 134 | if (_events != nil) { 135 | return nil; 136 | } 137 | _events = events; 138 | return nil; 139 | } 140 | 141 | - (FlutterError *_Nullable)onCancelWithArguments:(id _Nullable)arguments { 142 | if (_events == nil) { 143 | return nil; 144 | } 145 | _events = nil; 146 | return nil; 147 | } 148 | 149 | - (void)addEvent:(NSString *)event { 150 | if (_events != nil) { 151 | _events(event); 152 | } 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /ios/link_kit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # Run `pod lib lint link_kit.podspec` to validate before publishing. 4 | # 5 | 6 | pubspec = YAML.load_file(File.join('..', 'pubspec.yaml')) 7 | library_version = pubspec['version'].gsub('+', '-') 8 | 9 | current_dir = Dir.pwd 10 | calling_dir = File.dirname(__FILE__) 11 | project_dir = calling_dir.slice(0..(calling_dir.index('/.symlinks'))) 12 | flutter_project_dir = calling_dir.slice(0..(calling_dir.index('/ios/.symlinks'))) 13 | cfg = YAML.load_file(File.join(flutter_project_dir, 'pubspec.yaml')) 14 | if cfg['link_kit'] && cfg['link_kit']['deep_link'] && URI.parse(cfg['link_kit']['deep_link']).scheme 15 | deep_link = cfg['link_kit']['deep_link'] 16 | universal_link = nil 17 | options = "" 18 | if cfg['link_kit']['ios'] 19 | universal_link = cfg['link_kit']['ios']['universal_link'] 20 | options = "-u #{universal_link}" 21 | end 22 | system("ruby #{current_dir}/link_setup.rb -d #{deep_link} #{options} -p #{project_dir} -n Runner.xcodeproj") 23 | else 24 | abort("link_kit deep link is invalid, add code in pubspec.yaml:\nlink_kit:\n deep_link: ${your deep link scheme}:///\n android:\n app_link: https://${your applinks domain}/universal_link/${example_app}/link_kit/ # 可选配置\n ios:\n universal_link: https://${your applinks domain}/universal_link/${example_app}/link_kit/ # 可选配置\n") 25 | end 26 | 27 | Pod::Spec.new do |s| 28 | s.name = 'link_kit' 29 | s.version = library_version 30 | s.summary = pubspec['description'] 31 | s.description = pubspec['description'] 32 | s.homepage = pubspec['homepage'] 33 | s.license = { :file => '../LICENSE' } 34 | s.author = { 'Your Company' => 'email@example.com' } 35 | s.source = { :path => '.' } 36 | s.source_files = 'Classes/**/*' 37 | s.public_header_files = 'Classes/**/*.h' 38 | s.dependency 'Flutter' 39 | s.platform = :ios, '9.0' 40 | 41 | s.subspec 'vendor' do |sp| 42 | definitions_options = "" 43 | if universal_link 44 | definitions_options = " LINK_KIT_UNIVERSAL_LINK=\\@\\\"#{universal_link.gsub('/', '\/')}\\\"" 45 | end 46 | sp.pod_target_xcconfig = { 47 | 'GCC_PREPROCESSOR_DEFINITIONS' => "LINK_KIT_DEEP_LINK_SCHEME=\\@\\\"#{URI.parse(deep_link).scheme}\\\"#{definitions_options}" 48 | } 49 | end 50 | 51 | # Flutter.framework does not contain a i386 slice. 52 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } 53 | end 54 | -------------------------------------------------------------------------------- /ios/link_setup.rb: -------------------------------------------------------------------------------- 1 | # 2 | # 参考文献 3 | # https://github.com/firebase/flutterfire/blob/master/packages/firebase_crashlytics/firebase_crashlytics/ios/crashlytics_add_upload_symbols 4 | # https://github.com/MagicalWater/Base-APP-Env/blob/master/fastlane/actions/xcode_parse.rb 5 | # 6 | 7 | require 'xcodeproj' 8 | require 'plist' 9 | require 'optparse' 10 | require 'uri' 11 | 12 | # Dictionary to hold command line arguments 13 | options_dict = {} 14 | 15 | # Parse command line arguments into options_dict 16 | OptionParser.new do |options| 17 | options.banner = "Setup the Link to an Xcode target." 18 | 19 | options.on("-p", "--projectDirectory=DIRECTORY", String, "Directory of the Xcode project") do |dir| 20 | options_dict[:project_dir] = dir 21 | end 22 | 23 | options.on("-n", "--projectName=NAME", String, "Name of the Xcode project (ex: Runner.xcodeproj)") do |name| 24 | options_dict[:project_name] = name 25 | end 26 | 27 | options.on("-d", "--deepLink=DEEPLINK", String, "Deep Link for App") do |opts| 28 | options_dict[:deep_link] = opts 29 | end 30 | 31 | options.on("-u", "--universalLink=UNIVERSALLINK", String, "Universal Link for App") do |opts| 32 | options_dict[:universal_link] = opts 33 | end 34 | end.parse! 35 | 36 | # Minimum required arguments are a project directory and project name 37 | unless (options_dict[:project_dir] and options_dict[:project_name]) 38 | abort("Must provide a project directory and project name.\n") 39 | end 40 | 41 | # Path to the Xcode project to modify 42 | project_path = File.join(options_dict[:project_dir], options_dict[:project_name]) 43 | 44 | unless (File.exist?(project_path)) 45 | abort("Project at #{project_path} does not exist. Please check paths manually.\n"); 46 | end 47 | 48 | # Actually open and modify the project 49 | project = Xcodeproj::Project.open(project_path) 50 | project.targets.each do |target| 51 | if target.name == "Runner" 52 | deep_link = options_dict[:deep_link] 53 | universal_link = options_dict[:universal_link] 54 | 55 | sectionObject = {} 56 | project.objects.each do |object| 57 | if object.uuid == target.uuid 58 | sectionObject = object 59 | break 60 | end 61 | end 62 | sectionObject.build_configurations.each do |config| 63 | infoplist = config.build_settings["INFOPLIST_FILE"] 64 | if !infoplist 65 | abort("INFOPLIST_FILE is not exist\n") 66 | end 67 | infoplistFile = File.join(options_dict[:project_dir], infoplist) 68 | if !File.exist?(infoplistFile) 69 | abort("#{infoplist} is not exist\n") 70 | end 71 | result = Plist.parse_xml(infoplistFile, marshal: false) 72 | if !result 73 | result = {} 74 | end 75 | urlTypes = result["CFBundleURLTypes"] 76 | if !urlTypes 77 | urlTypes = [] 78 | result["CFBundleURLTypes"] = urlTypes 79 | end 80 | isUrlTypeExist = urlTypes.any? { |urlType| urlType["CFBundleURLSchemes"] && (urlType["CFBundleURLSchemes"].include? URI.parse(deep_link).scheme) } 81 | if !isUrlTypeExist 82 | urlTypes << { 83 | "CFBundleTypeRole": "Editor", 84 | "CFBundleURLName": "link", 85 | "CFBundleURLSchemes": [ URI.parse(deep_link).scheme ] 86 | } 87 | File.write(infoplistFile, Plist::Emit.dump(result)) 88 | end 89 | end 90 | if universal_link 91 | applinks = "applinks:#{URI.parse(universal_link).host}" 92 | sectionObject.build_configurations.each do |config| 93 | codeSignEntitlements = config.build_settings["CODE_SIGN_ENTITLEMENTS"] 94 | if !codeSignEntitlements 95 | codeSignEntitlements = "Runner/Runner.entitlements" 96 | config.build_settings["CODE_SIGN_ENTITLEMENTS"] = codeSignEntitlements 97 | project.save() 98 | end 99 | codeSignEntitlementsFile = File.join(options_dict[:project_dir], codeSignEntitlements) 100 | if !File.exist?(codeSignEntitlementsFile) 101 | content = Plist::Emit.dump({}) 102 | File.write(codeSignEntitlementsFile, content) 103 | end 104 | runnerTargetMainGroup = project.main_group.find_subpath('Runner', false) 105 | isRefExist = runnerTargetMainGroup.files.any? { |file| file.path.include? File.basename(codeSignEntitlementsFile) } 106 | if !isRefExist 107 | runnerTargetMainGroup.new_reference(File.basename(codeSignEntitlementsFile)) 108 | project.save() 109 | end 110 | result = Plist.parse_xml(codeSignEntitlementsFile, marshal: false) 111 | if !result 112 | result = {} 113 | end 114 | domains = result["com.apple.developer.associated-domains"] 115 | if !domains 116 | domains = [] 117 | result["com.apple.developer.associated-domains"] = domains 118 | end 119 | isApplinksExist = domains.include? applinks 120 | if !isApplinksExist 121 | domains << applinks 122 | File.write(codeSignEntitlementsFile, Plist::Emit.dump(result)) 123 | end 124 | end 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /lib/link_kit.dart: -------------------------------------------------------------------------------- 1 | library link_kit; 2 | 3 | export 'src/link_kit_platform_interface.dart'; 4 | -------------------------------------------------------------------------------- /lib/link_kit_platform_interface.dart: -------------------------------------------------------------------------------- 1 | library link_kit_platform_interface; 2 | 3 | export 'src/link_kit_method_channel.dart'; 4 | export 'src/link_kit_platform_interface.dart'; 5 | -------------------------------------------------------------------------------- /lib/src/link_kit_method_channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:link_kit/src/link_kit_platform_interface.dart'; 4 | 5 | /// An implementation of [LinkKitPlatform] that uses method channels. 6 | class MethodChannelLinkKit extends LinkKitPlatform { 7 | /// The method channel used to interact with the native platform. 8 | @visibleForTesting 9 | final MethodChannel methodChannel = 10 | const MethodChannel('v7lin.github.io/link_kit'); 11 | @visibleForTesting 12 | final EventChannel linkClickEventChannel = 13 | const EventChannel('v7lin.github.io/link_kit#click_event'); 14 | 15 | @override 16 | Future getInitialLink() { 17 | return methodChannel.invokeMethod('getInitialLink'); 18 | } 19 | 20 | Stream? _onLinkClickStream; 21 | 22 | @override 23 | Stream linkClickStream() { 24 | _onLinkClickStream ??= 25 | linkClickEventChannel.receiveBroadcastStream().map((dynamic event) { 26 | return event as String; 27 | }); 28 | return _onLinkClickStream!; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/src/link_kit_platform_interface.dart: -------------------------------------------------------------------------------- 1 | import 'package:link_kit/src/link_kit_method_channel.dart'; 2 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 3 | 4 | abstract class LinkKitPlatform extends PlatformInterface { 5 | /// Constructs a LinkKitPlatform. 6 | LinkKitPlatform() : super(token: _token); 7 | 8 | static final Object _token = Object(); 9 | 10 | static LinkKitPlatform _instance = MethodChannelLinkKit(); 11 | 12 | /// The default instance of [LinkKitPlatform] to use. 13 | /// 14 | /// Defaults to [MethodChannelLinkKit]. 15 | static LinkKitPlatform get instance => _instance; 16 | 17 | /// Platform-specific implementations should set this with their own 18 | /// platform-specific class that extends [LinkKitPlatform] when 19 | /// they register themselves. 20 | static set instance(LinkKitPlatform instance) { 21 | PlatformInterface.verifyToken(instance, _token); 22 | _instance = instance; 23 | } 24 | 25 | Future getInitialLink() { 26 | throw UnimplementedError('getInitialLink() has not been implemented.'); 27 | } 28 | 29 | Stream linkClickStream() { 30 | throw UnimplementedError('linkClickStream() has not been implemented.'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: link_kit 2 | description: Flutter plugin for App/Deep Link. 3 | version: 1.0.1 4 | # author: v7lin 5 | homepage: https://github.com/RxReader/link_kit 6 | repository: https://github.com/RxReader/link_kit.git 7 | issue_tracker: https://github.com/RxReader/link_kit/issues 8 | 9 | environment: 10 | sdk: ">=2.17.6 <3.0.0" 11 | flutter: ">=2.5.0" 12 | 13 | dependencies: 14 | flutter: 15 | sdk: flutter 16 | plugin_platform_interface: ^2.0.2 17 | 18 | dev_dependencies: 19 | flutter_test: 20 | sdk: flutter 21 | flutter_lints: ^2.0.0 22 | 23 | # For information on the generic Dart part of this file, see the 24 | # following page: https://dart.dev/tools/pub/pubspec 25 | 26 | # The following section is specific to Flutter packages. 27 | flutter: 28 | # This section identifies this Flutter project as a plugin project. 29 | # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) 30 | # which should be registered in the plugin registry. This is required for 31 | # using method channels. 32 | # The Android 'package' specifies package in which the registered class is. 33 | # This is required for using method channels on Android. 34 | # The 'ffiPlugin' specifies that native code should be built and bundled. 35 | # This is required for using `dart:ffi`. 36 | # All these are used by the tooling to maintain consistency when 37 | # adding or updating assets for this project. 38 | plugin: 39 | platforms: 40 | android: 41 | package: io.github.v7lin.link_kit 42 | pluginClass: LinkKitPlugin 43 | ios: 44 | pluginClass: LinkKitPlugin 45 | 46 | # To add assets to your plugin package, add an assets section, like this: 47 | # assets: 48 | # - images/a_dot_burr.jpeg 49 | # - images/a_dot_ham.jpeg 50 | # 51 | # For details regarding assets in packages, see 52 | # https://flutter.dev/assets-and-images/#from-packages 53 | # 54 | # An image asset can refer to one or more resolution-specific "variants", see 55 | # https://flutter.dev/assets-and-images/#resolution-aware 56 | 57 | # To add custom fonts to your plugin package, add a fonts section here, 58 | # in this "flutter" section. Each entry in this list should have a 59 | # "family" key with the font family name, and a "fonts" key with a 60 | # list giving the asset and other descriptors for the font. For 61 | # example: 62 | # fonts: 63 | # - family: Schyler 64 | # fonts: 65 | # - asset: fonts/Schyler-Regular.ttf 66 | # - asset: fonts/Schyler-Italic.ttf 67 | # style: italic 68 | # - family: Trajan Pro 69 | # fonts: 70 | # - asset: fonts/TrajanPro.ttf 71 | # - asset: fonts/TrajanPro_Bold.ttf 72 | # weight: 700 73 | # 74 | # For details regarding fonts in packages, see 75 | # https://flutter.dev/custom-fonts/#from-packages 76 | -------------------------------------------------------------------------------- /test/link_kit_method_channel_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:link_kit/src/link_kit_method_channel.dart'; 4 | 5 | void main() { 6 | final MethodChannelLinkKit platform = MethodChannelLinkKit(); 7 | const MethodChannel channel = MethodChannel('v7lin.github.io/link_kit'); 8 | 9 | TestWidgetsFlutterBinding.ensureInitialized(); 10 | 11 | setUp(() { 12 | channel.setMockMethodCallHandler((MethodCall call) async { 13 | switch (call.method) { 14 | case 'getInitialLink': 15 | return null; 16 | } 17 | }); 18 | }); 19 | 20 | tearDown(() { 21 | channel.setMockMethodCallHandler(null); 22 | }); 23 | 24 | test('getInitialLink', () async { 25 | expect(await platform.getInitialLink(), null); 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /test/link_kit_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:link_kit/src/link_kit_method_channel.dart'; 3 | import 'package:link_kit/src/link_kit_platform_interface.dart'; 4 | import 'package:plugin_platform_interface/plugin_platform_interface.dart'; 5 | 6 | class MockLinkKitPlatform 7 | with MockPlatformInterfaceMixin 8 | implements LinkKitPlatform { 9 | @override 10 | Future getInitialLink() async { 11 | return null; 12 | } 13 | 14 | @override 15 | Stream linkClickStream() { 16 | throw UnimplementedError(); 17 | } 18 | } 19 | 20 | void main() { 21 | final LinkKitPlatform initialPlatform = LinkKitPlatform.instance; 22 | 23 | test('$MethodChannelLinkKit is the default instance', () { 24 | expect(initialPlatform, isInstanceOf()); 25 | }); 26 | 27 | test('getInitialLink', () async { 28 | final MockLinkKitPlatform fakePlatform = MockLinkKitPlatform(); 29 | LinkKitPlatform.instance = fakePlatform; 30 | 31 | expect(await LinkKitPlatform.instance.getInitialLink(), null); 32 | }); 33 | } 34 | --------------------------------------------------------------------------------