├── .gitignore
├── .metadata
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── .gitignore
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── kotlin
│ └── cn
│ └── nekocode
│ └── h5pay
│ └── H5payPlugin.kt
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ │ └── cn
│ │ │ │ │ └── nekocode
│ │ │ │ │ └── h5pay_example
│ │ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ │ ├── 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
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ ├── settings.gradle
│ └── settings_aar.gradle
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Flutter.podspec
│ │ └── Release.xcconfig
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── 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-Bridging-Header.h
├── lib
│ └── main.dart
└── pubspec.yaml
├── image
└── screenshot.gif
├── ios
├── .gitignore
├── Assets
│ └── .gitkeep
├── Classes
│ ├── H5payPlugin.h
│ ├── H5payPlugin.m
│ └── SwiftH5payPlugin.swift
└── h5pay.podspec
├── lib
├── h5pay.dart
└── src
│ ├── h5pay_channel.dart
│ ├── h5pay_dialog.dart
│ ├── h5pay_widget.dart
│ └── utils.dart
├── pubspec.yaml
└── test
└── h5pay_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # https://github.com/flutter/plugins/blob/master/.gitignore
2 | .DS_Store
3 | .idea/
4 | .vscode/
5 |
6 | .packages
7 | .pub/
8 | .dart_tool/
9 | pubspec.lock
10 | flutter_export_environment.sh
11 |
12 | Podfile
13 | Podfile.lock
14 | Pods/
15 | .symlinks/
16 | **/Flutter/App.framework/
17 | **/Flutter/Flutter.framework/
18 | **/Flutter/Generated.xcconfig
19 | **/Flutter/flutter_assets/
20 | ServiceDefinitions.json
21 | xcuserdata/
22 | *.xcworkspace
23 | **/DerivedData/
24 |
25 | local.properties
26 | keystore.properties
27 | .gradle/
28 | gradlew
29 | gradlew.bat
30 | gradle-wrapper.jar
31 | *.iml
32 |
33 | GeneratedPluginRegistrant.h
34 | GeneratedPluginRegistrant.m
35 | GeneratedPluginRegistrant.java
36 | build/
37 | .flutter-plugins
38 | .flutter-plugins-dependencies
39 |
40 | .project
41 | .classpath
42 | .settings
--------------------------------------------------------------------------------
/.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 and should not be manually edited.
5 |
6 | version:
7 | revision: 1946fc4da0f80c522d7e3ae7d4f7309908ed86f2
8 | channel: dev
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # https://medium.com/flutter/test-flutter-apps-on-travis-3fd5142ecd8c
2 |
3 | os:
4 | - linux
5 | sudo: false
6 | addons:
7 | apt:
8 | # Flutter depends on /usr/lib/x86_64-linux-gnu/libstdc++.so.6 version GLIBCXX_3.4.18
9 | sources:
10 | - ubuntu-toolchain-r-test # if we don't specify this, the libstdc++6 we get is the wrong version
11 | packages:
12 | - libstdc++6
13 | - fonts-droid-fallback
14 | before_script:
15 | - git clone https://github.com/flutter/flutter.git -b stable
16 | - ./flutter/bin/flutter doctor
17 | script:
18 | - ./flutter/bin/flutter test
19 | cache:
20 | directories:
21 | - $HOME/.pub-cache
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 1.1.1
2 |
3 | * Fix the issue of unable to jump on Android
4 |
5 | ## 1.1.0
6 |
7 | * Add support for setting http headers
8 |
9 | ## 1.0.1
10 |
11 | * Just bump version
12 |
13 | ## 1.0.0-nullsafety.0
14 |
15 | * Migrate to null safety
16 |
17 | ## 0.5.0
18 |
19 | * Refactor: getPaymentUrl => getPaymentArguments
20 |
21 | ## 0.4.2
22 |
23 | * Just update the README
24 |
25 | ## 0.4.1
26 |
27 | * Revert: use future to get payment url
28 |
29 | ## 0.4.0
30 |
31 | * Replace the 'getH5Url' argument with 'paymentUrl'
32 | * Expose some util methods from platform plugins
33 |
34 | ## 0.2.0
35 |
36 | * Handle unmounted state of widget
37 |
38 | ## 0.1.0
39 |
40 | * Initial release
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # h5pay
2 | [](https://travis-ci.com/nekocode/h5pay-flutter)
3 | [](https://pub.dev/packages/h5pay)
4 |
5 | A H5 payment (such as Alipay, WeChat Pay) plugin for flutter.
6 |
7 |
8 |
9 | ## Usage
10 |
11 | Use the `showH5PayDialog` method to show a loading dialog and jump to payment app. When user switches from payment app back to your app, you can check payment result with your server in the `verifyResult` callback (Optional).
12 |
13 | ```dart
14 | import 'package:h5pay/h5pay.dart';
15 |
16 | final PaymentStatus status = await showH5PayDialog(
17 | context: context,
18 | // You can get payment url (normally is http or payment app scheme) from server in the getPaymentArguments callback
19 | getPaymentArguments: () async => PaymentArguments(
20 | url: 'https://is.gd/4cLE6j',
21 | redirectSchemes: ['alipay', 'alipays', 'weixin', 'wechat'],
22 | httpHeaders: {
23 | 'referer': 'https://xxx',
24 | },
25 | ),
26 | verifyResult: () async => true, // check order result with your server
27 | );
28 | if (status == PaymentStatus.success) {
29 | // Do something
30 | }
31 | ```
32 |
33 | Values of `PaymentStatus`:
34 |
35 | ```dart
36 | enum PaymentStatus {
37 | idle,
38 | gettingArguments,
39 | getArgumentsFail,
40 | launchingUrl,
41 | cantLaunchUrl, // Maybe target payment app is not installed
42 | launchUrlTimeout, // Maybe redirecting url is fail
43 | jumping,
44 | jumpTimeout,
45 | verifying,
46 | success,
47 | fail,
48 | }
49 | ```
50 |
51 | ### Notes
52 |
53 | * In iOS, for allowing to jump to the payment app from your app, you must add schemes of the payment apps into the `Info.plist` file. Just like:
54 |
55 | ```xml
56 | LSApplicationQueriesSchemes
57 |
58 | wechat
59 | weixin
60 | alipay
61 | alipays
62 |
63 | ```
64 |
65 | ### Advanced
66 |
67 | If you have more complex requirements, you can use the `H5PayWidget`. Check the [example](example) for more detail.
68 |
69 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | group 'cn.nekocode.h5pay'
2 | version '1.0-SNAPSHOT'
3 |
4 | buildscript {
5 | ext.kotlin_version = '1.5.31'
6 | repositories {
7 | google()
8 | jcenter()
9 | }
10 |
11 | dependencies {
12 | classpath 'com.android.tools.build:gradle:7.0.2'
13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14 | }
15 | }
16 |
17 | rootProject.allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | }
22 | }
23 |
24 | apply plugin: 'com.android.library'
25 | apply plugin: 'kotlin-android'
26 |
27 | android {
28 | compileSdkVersion 30
29 |
30 | sourceSets {
31 | main.java.srcDirs += 'src/main/kotlin'
32 | }
33 | defaultConfig {
34 | minSdkVersion 16
35 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
36 | }
37 | lintOptions {
38 | disable 'InvalidPackage'
39 | }
40 | }
41 |
42 | dependencies {
43 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
44 | }
45 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
6 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'h5pay'
2 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/android/src/main/kotlin/cn/nekocode/h5pay/H5payPlugin.kt:
--------------------------------------------------------------------------------
1 | package cn.nekocode.h5pay
2 |
3 | import android.annotation.SuppressLint
4 | import android.annotation.TargetApi
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.pm.ApplicationInfo
8 | import android.net.Uri
9 | import android.os.Build
10 | import android.view.View
11 | import android.webkit.WebResourceRequest
12 | import android.webkit.WebView
13 | import android.webkit.WebViewClient
14 | import io.flutter.embedding.engine.plugins.FlutterPlugin
15 | import io.flutter.plugin.common.MethodCall
16 | import io.flutter.plugin.common.MethodChannel
17 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler
18 | import io.flutter.plugin.common.MethodChannel.Result
19 |
20 | class H5payPlugin : FlutterPlugin, MethodCallHandler {
21 | private lateinit var channel: MethodChannel
22 | private lateinit var binding: FlutterPlugin.FlutterPluginBinding
23 | private var targetSchemes: Iterable = emptyList()
24 | private var httpHeaders: Map = emptyMap()
25 | private var webView: WebView? = null
26 | private var result: Result? = null
27 |
28 | override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
29 | this.binding = binding
30 | channel = MethodChannel(binding.binaryMessenger, "h5pay")
31 | channel.setMethodCallHandler(this)
32 | }
33 |
34 | override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
35 | channel.setMethodCallHandler(null)
36 | }
37 |
38 | override fun onMethodCall(call: MethodCall, result: Result) {
39 | when (call.method) {
40 | "launchRedirectUrl" -> {
41 | launchRedirectUrl(call, result)
42 | }
43 | "launchUrl" -> {
44 | launchUrl(call, result)
45 | }
46 | "canLaunch" -> {
47 | canLaunch(call, result)
48 | }
49 | else -> {
50 | result.notImplemented()
51 | }
52 | }
53 | }
54 |
55 | private fun launchRedirectUrl(call: MethodCall, result: Result) {
56 | val arguments = call.arguments as? HashMap<*, *>
57 | targetSchemes = (arguments?.get("targetSchemes") as? Iterable<*>)
58 | ?.filterIsInstance()
59 | ?: emptyList()
60 | @Suppress("UNCHECKED_CAST")
61 | httpHeaders = (arguments?.get("httpHeaders") as? Map) ?: emptyMap()
62 |
63 | // Try to launch url directly
64 | val url = (arguments?.get("url") as? String)
65 | if (url == null) {
66 | result.success(false)
67 | return
68 | }
69 | if (Utils.hasScheme(url, targetSchemes)) {
70 | result.success(Utils.launchUrl(binding.applicationContext, url))
71 | return
72 | }
73 |
74 | initWebView()
75 |
76 | this.result = result
77 | webView!!.run {
78 | stopLoading()
79 | loadUrl(url, httpHeaders)
80 | }
81 | }
82 |
83 | private fun launchUrl(call: MethodCall, result: Result) {
84 | val arguments = call.arguments as? HashMap<*, *>
85 | val url = arguments?.get("url") as? String
86 | result.success(Utils.launchUrl(binding.applicationContext, url))
87 | }
88 |
89 | private fun canLaunch(call: MethodCall, result: Result) {
90 | val arguments = call.arguments as? HashMap<*, *>
91 | val url = arguments?.get("url") as? String
92 | if (url == null) {
93 | result.success(false)
94 | return
95 | }
96 | result.success(Utils.canLaunch(binding.applicationContext, url))
97 | }
98 |
99 | @SuppressLint("SetJavaScriptEnabled")
100 | private fun initWebView() {
101 | if (webView != null) {
102 | return
103 | }
104 |
105 | val context = binding.applicationContext
106 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
107 | if (0 != (context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE)) {
108 | WebView.setWebContentsDebuggingEnabled(true)
109 | }
110 | }
111 |
112 | val webView = WebView(context)
113 | webView.visibility = View.GONE
114 | webView.settings.javaScriptEnabled = true
115 | webView.settings.domStorageEnabled = true
116 | webView.settings.allowFileAccessFromFileURLs = true
117 | webView.settings.allowUniversalAccessFromFileURLs = true
118 | webView.settings.loadsImagesAutomatically = false
119 | webView.settings.blockNetworkImage = false
120 | webView.webViewClient = Client()
121 | this.webView = webView
122 | }
123 |
124 | inner class Client : WebViewClient() {
125 | override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
126 | return shouldOverrideUrlLoading(url)
127 | }
128 |
129 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
130 | override fun shouldOverrideUrlLoading(
131 | view: WebView?,
132 | request: WebResourceRequest?
133 | ): Boolean {
134 | val url = request?.url?.toString()
135 | return shouldOverrideUrlLoading(url)
136 | }
137 |
138 | private fun shouldOverrideUrlLoading(url: String?): Boolean {
139 | if (Utils.hasScheme(url, targetSchemes)) {
140 | result?.success(Utils.launchUrl(binding.applicationContext, url))
141 | return true
142 | }
143 | return false
144 | }
145 | }
146 | }
147 |
148 | object Utils {
149 | private const val FALLBACK_COMPONENT_NAME =
150 | "{com.android.fallback/com.android.fallback.Fallback}"
151 |
152 | fun launchUrl(context: Context, url: String?): Boolean {
153 | return if (!canLaunch(context, url)) {
154 | false
155 | } else {
156 | try {
157 | val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url));
158 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
159 | context.startActivity(intent)
160 | true
161 | } catch (_: Exception) {
162 | false
163 | }
164 | }
165 | }
166 |
167 | fun canLaunch(context: Context, url: String?): Boolean {
168 | url ?: return false
169 | val launchIntent = Intent(Intent.ACTION_VIEW).apply {
170 | data = Uri.parse(url)
171 | }
172 | val componentName = launchIntent.resolveActivity(context.packageManager)
173 |
174 | return componentName != null &&
175 | FALLBACK_COMPONENT_NAME != componentName.toShortString()
176 | }
177 |
178 | fun hasScheme(url: String?, targetSchemes: Iterable): Boolean {
179 | url ?: return false
180 | for (scheme in targetSchemes) {
181 | if (!url.startsWith("$scheme:")) {
182 | continue
183 | }
184 | return true
185 | }
186 | return false
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 |
32 | # Web related
33 | lib/generated_plugin_registrant.dart
34 |
35 | # Exceptions to above rules.
36 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
37 |
--------------------------------------------------------------------------------
/example/.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 and should not be manually edited.
5 |
6 | version:
7 | revision: 1946fc4da0f80c522d7e3ae7d4f7309908ed86f2
8 | channel: dev
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # h5pay_example
2 |
3 | Demonstrates how to use the h5pay 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://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
--------------------------------------------------------------------------------
/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 30
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | applicationId "cn.nekocode.h5pay_example"
41 | minSdkVersion 16
42 | versionCode flutterVersionCode.toInteger()
43 | versionName flutterVersionName
44 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
45 | }
46 |
47 | buildTypes {
48 | release {
49 | // TODO: Add your own signing config for the release build.
50 | // Signing with the debug keys for now, so `flutter run --release` works.
51 | signingConfig signingConfigs.debug
52 | }
53 | }
54 | }
55 |
56 | flutter {
57 | source '../..'
58 | }
59 |
60 | dependencies {
61 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
62 | testImplementation 'junit:junit:4.12'
63 | androidTestImplementation 'androidx.test:runner:1.1.1'
64 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
65 | }
66 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
11 |
16 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
35 |
36 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/example/android/app/src/main/kotlin/cn/nekocode/h5pay_example/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package cn.nekocode.h5pay_example
2 |
3 | import io.flutter.embedding.android.FlutterActivity;
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.5.31'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.0.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
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 | android.enableR8=true
5 |
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Mar 27 17:53:17 CST 2020
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.0.2-all.zip
7 |
--------------------------------------------------------------------------------
/example/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/example/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Generated.xcconfig
20 | Flutter/app.flx
21 | Flutter/app.zip
22 | Flutter/flutter_assets/
23 | Flutter/flutter_export_environment.sh
24 | ServiceDefinitions.json
25 | Runner/GeneratedPluginRegistrant.*
26 |
27 | # Exceptions to above rules.
28 | !default.mode1v3
29 | !default.mode2v3
30 | !default.pbxuser
31 | !default.perspectivev3
32 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | 9.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/Flutter.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # NOTE: This podspec is NOT to be published. It is only used as a local source!
3 | # This is a generated file; do not edit or check into version control.
4 | #
5 |
6 | Pod::Spec.new do |s|
7 | s.name = 'Flutter'
8 | s.version = '1.0.0'
9 | s.summary = 'High-performance, high-fidelity mobile apps.'
10 | s.homepage = 'https://flutter.io'
11 | s.license = { :type => 'MIT' }
12 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
13 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
14 | s.ios.deployment_target = '9.0'
15 | # Framework linking is handled by Flutter tooling, not CocoaPods.
16 | # Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
17 | s.vendored_frameworks = 'path/to/nothing'
18 | end
19 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
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 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | B23475D7AF1DC6C8B5044C31 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1588BAF74BF9B28F329E0E6B /* Pods_Runner.framework */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | name = "Embed Frameworks";
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXCopyFilesBuildPhase section */
31 |
32 | /* Begin PBXFileReference section */
33 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
34 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
35 | 1588BAF74BF9B28F329E0E6B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
37 | 5CD299C846584808A42E53B6 /* 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 = ""; };
38 | 69509F9C50D8DE03936A48C7 /* 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 = ""; };
39 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
40 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
41 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
42 | 870474766FD64077A4632910 /* 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 = ""; };
43 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
44 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
45 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
46 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
47 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
48 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
49 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
50 | /* End PBXFileReference section */
51 |
52 | /* Begin PBXFrameworksBuildPhase section */
53 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
54 | isa = PBXFrameworksBuildPhase;
55 | buildActionMask = 2147483647;
56 | files = (
57 | B23475D7AF1DC6C8B5044C31 /* Pods_Runner.framework in Frameworks */,
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | /* End PBXFrameworksBuildPhase section */
62 |
63 | /* Begin PBXGroup section */
64 | 9740EEB11CF90186004384FC /* Flutter */ = {
65 | isa = PBXGroup;
66 | children = (
67 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
68 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
69 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
70 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
71 | );
72 | name = Flutter;
73 | sourceTree = "";
74 | };
75 | 97C146E51CF9000F007C117D = {
76 | isa = PBXGroup;
77 | children = (
78 | 9740EEB11CF90186004384FC /* Flutter */,
79 | 97C146F01CF9000F007C117D /* Runner */,
80 | 97C146EF1CF9000F007C117D /* Products */,
81 | FA11FCB0DD8A86C785225185 /* Pods */,
82 | B22AC23DA418F21FC9618090 /* Frameworks */,
83 | );
84 | sourceTree = "";
85 | };
86 | 97C146EF1CF9000F007C117D /* Products */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146EE1CF9000F007C117D /* Runner.app */,
90 | );
91 | name = Products;
92 | sourceTree = "";
93 | };
94 | 97C146F01CF9000F007C117D /* Runner */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
98 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
99 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
100 | 97C147021CF9000F007C117D /* Info.plist */,
101 | 97C146F11CF9000F007C117D /* Supporting Files */,
102 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
103 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
104 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
105 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
106 | );
107 | path = Runner;
108 | sourceTree = "";
109 | };
110 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
111 | isa = PBXGroup;
112 | children = (
113 | );
114 | name = "Supporting Files";
115 | sourceTree = "";
116 | };
117 | B22AC23DA418F21FC9618090 /* Frameworks */ = {
118 | isa = PBXGroup;
119 | children = (
120 | 1588BAF74BF9B28F329E0E6B /* Pods_Runner.framework */,
121 | );
122 | name = Frameworks;
123 | sourceTree = "";
124 | };
125 | FA11FCB0DD8A86C785225185 /* Pods */ = {
126 | isa = PBXGroup;
127 | children = (
128 | 870474766FD64077A4632910 /* Pods-Runner.debug.xcconfig */,
129 | 5CD299C846584808A42E53B6 /* Pods-Runner.release.xcconfig */,
130 | 69509F9C50D8DE03936A48C7 /* Pods-Runner.profile.xcconfig */,
131 | );
132 | path = Pods;
133 | sourceTree = "";
134 | };
135 | /* End PBXGroup section */
136 |
137 | /* Begin PBXNativeTarget section */
138 | 97C146ED1CF9000F007C117D /* Runner */ = {
139 | isa = PBXNativeTarget;
140 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
141 | buildPhases = (
142 | B623D3E015095CCE157A4C2E /* [CP] Check Pods Manifest.lock */,
143 | 9740EEB61CF901F6004384FC /* Run Script */,
144 | 97C146EA1CF9000F007C117D /* Sources */,
145 | 97C146EB1CF9000F007C117D /* Frameworks */,
146 | 97C146EC1CF9000F007C117D /* Resources */,
147 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
148 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
149 | D1E37E9FEB65B98FE9B1F8DC /* [CP] Embed Pods Frameworks */,
150 | );
151 | buildRules = (
152 | );
153 | dependencies = (
154 | );
155 | name = Runner;
156 | productName = Runner;
157 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
158 | productType = "com.apple.product-type.application";
159 | };
160 | /* End PBXNativeTarget section */
161 |
162 | /* Begin PBXProject section */
163 | 97C146E61CF9000F007C117D /* Project object */ = {
164 | isa = PBXProject;
165 | attributes = {
166 | LastUpgradeCheck = 1020;
167 | ORGANIZATIONNAME = "The Chromium Authors";
168 | TargetAttributes = {
169 | 97C146ED1CF9000F007C117D = {
170 | CreatedOnToolsVersion = 7.3.1;
171 | LastSwiftMigration = 0910;
172 | };
173 | };
174 | };
175 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
176 | compatibilityVersion = "Xcode 3.2";
177 | developmentRegion = en;
178 | hasScannedForEncodings = 0;
179 | knownRegions = (
180 | en,
181 | Base,
182 | );
183 | mainGroup = 97C146E51CF9000F007C117D;
184 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
185 | projectDirPath = "";
186 | projectRoot = "";
187 | targets = (
188 | 97C146ED1CF9000F007C117D /* Runner */,
189 | );
190 | };
191 | /* End PBXProject section */
192 |
193 | /* Begin PBXResourcesBuildPhase section */
194 | 97C146EC1CF9000F007C117D /* Resources */ = {
195 | isa = PBXResourcesBuildPhase;
196 | buildActionMask = 2147483647;
197 | files = (
198 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
199 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
200 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
201 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
202 | );
203 | runOnlyForDeploymentPostprocessing = 0;
204 | };
205 | /* End PBXResourcesBuildPhase section */
206 |
207 | /* Begin PBXShellScriptBuildPhase section */
208 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
209 | isa = PBXShellScriptBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | );
213 | inputPaths = (
214 | );
215 | name = "Thin Binary";
216 | outputPaths = (
217 | );
218 | runOnlyForDeploymentPostprocessing = 0;
219 | shellPath = /bin/sh;
220 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
221 | };
222 | 9740EEB61CF901F6004384FC /* Run Script */ = {
223 | isa = PBXShellScriptBuildPhase;
224 | buildActionMask = 2147483647;
225 | files = (
226 | );
227 | inputPaths = (
228 | );
229 | name = "Run Script";
230 | outputPaths = (
231 | );
232 | runOnlyForDeploymentPostprocessing = 0;
233 | shellPath = /bin/sh;
234 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
235 | };
236 | B623D3E015095CCE157A4C2E /* [CP] Check Pods Manifest.lock */ = {
237 | isa = PBXShellScriptBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | );
241 | inputFileListPaths = (
242 | );
243 | inputPaths = (
244 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
245 | "${PODS_ROOT}/Manifest.lock",
246 | );
247 | name = "[CP] Check Pods Manifest.lock";
248 | outputFileListPaths = (
249 | );
250 | outputPaths = (
251 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
252 | );
253 | runOnlyForDeploymentPostprocessing = 0;
254 | shellPath = /bin/sh;
255 | 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";
256 | showEnvVarsInLog = 0;
257 | };
258 | D1E37E9FEB65B98FE9B1F8DC /* [CP] Embed Pods Frameworks */ = {
259 | isa = PBXShellScriptBuildPhase;
260 | buildActionMask = 2147483647;
261 | files = (
262 | );
263 | inputPaths = (
264 | "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
265 | "${BUILT_PRODUCTS_DIR}/h5pay/h5pay.framework",
266 | );
267 | name = "[CP] Embed Pods Frameworks";
268 | outputPaths = (
269 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/h5pay.framework",
270 | );
271 | runOnlyForDeploymentPostprocessing = 0;
272 | shellPath = /bin/sh;
273 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
274 | showEnvVarsInLog = 0;
275 | };
276 | /* End PBXShellScriptBuildPhase section */
277 |
278 | /* Begin PBXSourcesBuildPhase section */
279 | 97C146EA1CF9000F007C117D /* Sources */ = {
280 | isa = PBXSourcesBuildPhase;
281 | buildActionMask = 2147483647;
282 | files = (
283 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
284 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
285 | );
286 | runOnlyForDeploymentPostprocessing = 0;
287 | };
288 | /* End PBXSourcesBuildPhase section */
289 |
290 | /* Begin PBXVariantGroup section */
291 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
292 | isa = PBXVariantGroup;
293 | children = (
294 | 97C146FB1CF9000F007C117D /* Base */,
295 | );
296 | name = Main.storyboard;
297 | sourceTree = "";
298 | };
299 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
300 | isa = PBXVariantGroup;
301 | children = (
302 | 97C147001CF9000F007C117D /* Base */,
303 | );
304 | name = LaunchScreen.storyboard;
305 | sourceTree = "";
306 | };
307 | /* End PBXVariantGroup section */
308 |
309 | /* Begin XCBuildConfiguration section */
310 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
311 | isa = XCBuildConfiguration;
312 | buildSettings = {
313 | ALWAYS_SEARCH_USER_PATHS = NO;
314 | CLANG_ANALYZER_NONNULL = YES;
315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
316 | CLANG_CXX_LIBRARY = "libc++";
317 | CLANG_ENABLE_MODULES = YES;
318 | CLANG_ENABLE_OBJC_ARC = YES;
319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
320 | CLANG_WARN_BOOL_CONVERSION = YES;
321 | CLANG_WARN_COMMA = YES;
322 | CLANG_WARN_CONSTANT_CONVERSION = YES;
323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
325 | CLANG_WARN_EMPTY_BODY = YES;
326 | CLANG_WARN_ENUM_CONVERSION = YES;
327 | CLANG_WARN_INFINITE_RECURSION = YES;
328 | CLANG_WARN_INT_CONVERSION = YES;
329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
334 | CLANG_WARN_STRICT_PROTOTYPES = YES;
335 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
336 | CLANG_WARN_UNREACHABLE_CODE = YES;
337 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
339 | COPY_PHASE_STRIP = NO;
340 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
341 | ENABLE_NS_ASSERTIONS = NO;
342 | ENABLE_STRICT_OBJC_MSGSEND = YES;
343 | GCC_C_LANGUAGE_STANDARD = gnu99;
344 | GCC_NO_COMMON_BLOCKS = YES;
345 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
346 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
347 | GCC_WARN_UNDECLARED_SELECTOR = YES;
348 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
349 | GCC_WARN_UNUSED_FUNCTION = YES;
350 | GCC_WARN_UNUSED_VARIABLE = YES;
351 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
352 | MTL_ENABLE_DEBUG_INFO = NO;
353 | SDKROOT = iphoneos;
354 | SUPPORTED_PLATFORMS = iphoneos;
355 | TARGETED_DEVICE_FAMILY = "1,2";
356 | VALIDATE_PRODUCT = YES;
357 | };
358 | name = Profile;
359 | };
360 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
361 | isa = XCBuildConfiguration;
362 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
363 | buildSettings = {
364 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
365 | CLANG_ENABLE_MODULES = YES;
366 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
367 | ENABLE_BITCODE = NO;
368 | FRAMEWORK_SEARCH_PATHS = (
369 | "$(inherited)",
370 | "$(PROJECT_DIR)/Flutter",
371 | );
372 | INFOPLIST_FILE = Runner/Info.plist;
373 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
374 | LIBRARY_SEARCH_PATHS = (
375 | "$(inherited)",
376 | "$(PROJECT_DIR)/Flutter",
377 | );
378 | PRODUCT_BUNDLE_IDENTIFIER = cn.nekocode.h5payExample;
379 | PRODUCT_NAME = "$(TARGET_NAME)";
380 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
381 | SWIFT_VERSION = 4.0;
382 | VERSIONING_SYSTEM = "apple-generic";
383 | };
384 | name = Profile;
385 | };
386 | 97C147031CF9000F007C117D /* Debug */ = {
387 | isa = XCBuildConfiguration;
388 | buildSettings = {
389 | ALWAYS_SEARCH_USER_PATHS = NO;
390 | CLANG_ANALYZER_NONNULL = YES;
391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
392 | CLANG_CXX_LIBRARY = "libc++";
393 | CLANG_ENABLE_MODULES = YES;
394 | CLANG_ENABLE_OBJC_ARC = YES;
395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
396 | CLANG_WARN_BOOL_CONVERSION = YES;
397 | CLANG_WARN_COMMA = YES;
398 | CLANG_WARN_CONSTANT_CONVERSION = YES;
399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
401 | CLANG_WARN_EMPTY_BODY = YES;
402 | CLANG_WARN_ENUM_CONVERSION = YES;
403 | CLANG_WARN_INFINITE_RECURSION = YES;
404 | CLANG_WARN_INT_CONVERSION = YES;
405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
406 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
407 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
409 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
410 | CLANG_WARN_STRICT_PROTOTYPES = YES;
411 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
412 | CLANG_WARN_UNREACHABLE_CODE = YES;
413 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
414 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
415 | COPY_PHASE_STRIP = NO;
416 | DEBUG_INFORMATION_FORMAT = dwarf;
417 | ENABLE_STRICT_OBJC_MSGSEND = YES;
418 | ENABLE_TESTABILITY = YES;
419 | GCC_C_LANGUAGE_STANDARD = gnu99;
420 | GCC_DYNAMIC_NO_PIC = NO;
421 | GCC_NO_COMMON_BLOCKS = YES;
422 | GCC_OPTIMIZATION_LEVEL = 0;
423 | GCC_PREPROCESSOR_DEFINITIONS = (
424 | "DEBUG=1",
425 | "$(inherited)",
426 | );
427 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
428 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
429 | GCC_WARN_UNDECLARED_SELECTOR = YES;
430 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
431 | GCC_WARN_UNUSED_FUNCTION = YES;
432 | GCC_WARN_UNUSED_VARIABLE = YES;
433 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
434 | MTL_ENABLE_DEBUG_INFO = YES;
435 | ONLY_ACTIVE_ARCH = YES;
436 | SDKROOT = iphoneos;
437 | TARGETED_DEVICE_FAMILY = "1,2";
438 | };
439 | name = Debug;
440 | };
441 | 97C147041CF9000F007C117D /* Release */ = {
442 | isa = XCBuildConfiguration;
443 | buildSettings = {
444 | ALWAYS_SEARCH_USER_PATHS = NO;
445 | CLANG_ANALYZER_NONNULL = YES;
446 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
447 | CLANG_CXX_LIBRARY = "libc++";
448 | CLANG_ENABLE_MODULES = YES;
449 | CLANG_ENABLE_OBJC_ARC = YES;
450 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
451 | CLANG_WARN_BOOL_CONVERSION = YES;
452 | CLANG_WARN_COMMA = YES;
453 | CLANG_WARN_CONSTANT_CONVERSION = YES;
454 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
456 | CLANG_WARN_EMPTY_BODY = YES;
457 | CLANG_WARN_ENUM_CONVERSION = YES;
458 | CLANG_WARN_INFINITE_RECURSION = YES;
459 | CLANG_WARN_INT_CONVERSION = YES;
460 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
461 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
462 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
463 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
464 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
465 | CLANG_WARN_STRICT_PROTOTYPES = YES;
466 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
467 | CLANG_WARN_UNREACHABLE_CODE = YES;
468 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
469 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
470 | COPY_PHASE_STRIP = NO;
471 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
472 | ENABLE_NS_ASSERTIONS = NO;
473 | ENABLE_STRICT_OBJC_MSGSEND = YES;
474 | GCC_C_LANGUAGE_STANDARD = gnu99;
475 | GCC_NO_COMMON_BLOCKS = YES;
476 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
477 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
478 | GCC_WARN_UNDECLARED_SELECTOR = YES;
479 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
480 | GCC_WARN_UNUSED_FUNCTION = YES;
481 | GCC_WARN_UNUSED_VARIABLE = YES;
482 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
483 | MTL_ENABLE_DEBUG_INFO = NO;
484 | SDKROOT = iphoneos;
485 | SUPPORTED_PLATFORMS = iphoneos;
486 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
487 | TARGETED_DEVICE_FAMILY = "1,2";
488 | VALIDATE_PRODUCT = YES;
489 | };
490 | name = Release;
491 | };
492 | 97C147061CF9000F007C117D /* Debug */ = {
493 | isa = XCBuildConfiguration;
494 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
495 | buildSettings = {
496 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
497 | CLANG_ENABLE_MODULES = YES;
498 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
499 | ENABLE_BITCODE = NO;
500 | FRAMEWORK_SEARCH_PATHS = (
501 | "$(inherited)",
502 | "$(PROJECT_DIR)/Flutter",
503 | );
504 | INFOPLIST_FILE = Runner/Info.plist;
505 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
506 | LIBRARY_SEARCH_PATHS = (
507 | "$(inherited)",
508 | "$(PROJECT_DIR)/Flutter",
509 | );
510 | PRODUCT_BUNDLE_IDENTIFIER = cn.nekocode.h5payExample;
511 | PRODUCT_NAME = "$(TARGET_NAME)";
512 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
513 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
514 | SWIFT_VERSION = 4.0;
515 | VERSIONING_SYSTEM = "apple-generic";
516 | };
517 | name = Debug;
518 | };
519 | 97C147071CF9000F007C117D /* Release */ = {
520 | isa = XCBuildConfiguration;
521 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
522 | buildSettings = {
523 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
524 | CLANG_ENABLE_MODULES = YES;
525 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
526 | ENABLE_BITCODE = NO;
527 | FRAMEWORK_SEARCH_PATHS = (
528 | "$(inherited)",
529 | "$(PROJECT_DIR)/Flutter",
530 | );
531 | INFOPLIST_FILE = Runner/Info.plist;
532 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
533 | LIBRARY_SEARCH_PATHS = (
534 | "$(inherited)",
535 | "$(PROJECT_DIR)/Flutter",
536 | );
537 | PRODUCT_BUNDLE_IDENTIFIER = cn.nekocode.h5payExample;
538 | PRODUCT_NAME = "$(TARGET_NAME)";
539 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
540 | SWIFT_VERSION = 4.0;
541 | VERSIONING_SYSTEM = "apple-generic";
542 | };
543 | name = Release;
544 | };
545 | /* End XCBuildConfiguration section */
546 |
547 | /* Begin XCConfigurationList section */
548 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
549 | isa = XCConfigurationList;
550 | buildConfigurations = (
551 | 97C147031CF9000F007C117D /* Debug */,
552 | 97C147041CF9000F007C117D /* Release */,
553 | 249021D3217E4FDB00AE95B9 /* Profile */,
554 | );
555 | defaultConfigurationIsVisible = 0;
556 | defaultConfigurationName = Release;
557 | };
558 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
559 | isa = XCConfigurationList;
560 | buildConfigurations = (
561 | 97C147061CF9000F007C117D /* Debug */,
562 | 97C147071CF9000F007C117D /* Release */,
563 | 249021D4217E4FDB00AE95B9 /* Profile */,
564 | );
565 | defaultConfigurationIsVisible = 0;
566 | defaultConfigurationName = Release;
567 | };
568 | /* End XCConfigurationList section */
569 | };
570 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
571 | }
572 |
--------------------------------------------------------------------------------
/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/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/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 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | h5pay_example
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 | LSApplicationQueriesSchemes
45 |
46 | wechat
47 | weixin
48 | alipay
49 | alipays
50 | mailto
51 | sms
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:h5pay/h5pay.dart';
3 |
4 | void main() => runApp(MaterialApp(home: IndexPage()));
5 |
6 | class IndexPage extends StatelessWidget {
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: const Text('Example app'),
12 | ),
13 | body: Center(
14 | child: TextButton(
15 | child: Text('Plugin Test'),
16 | onPressed: () {
17 | Navigator.push(
18 | context,
19 | MaterialPageRoute(builder: (context) => MainPage()),
20 | );
21 | },
22 | ),
23 | ),
24 | );
25 | }
26 | }
27 |
28 | class MainPage extends StatelessWidget {
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | appBar: AppBar(
33 | title: const Text('Plugin Test'),
34 | ),
35 | body: MainBody(),
36 | );
37 | }
38 | }
39 |
40 | class MainBody extends StatelessWidget {
41 | @override
42 | Widget build(BuildContext context) {
43 | return Center(
44 | child: Column(
45 | mainAxisAlignment: MainAxisAlignment.center,
46 | children: [
47 | H5PayWidget(
48 | getPaymentArguments: () async => PaymentArguments(
49 | url: 'https://is.gd/4cLE6j',
50 | redirectSchemes: ['sms'],
51 | httpHeaders: {
52 | 'referer': 'https://is.gd',
53 | },
54 | ),
55 | verifyResult: () async => true,
56 | builder: (context, status, controller) => TextButton(
57 | onPressed: status != PaymentStatus.gettingArguments &&
58 | status != PaymentStatus.launchingUrl &&
59 | status != PaymentStatus.jumping &&
60 | status != PaymentStatus.verifying
61 | ? () async {
62 | controller.launch();
63 | }
64 | : null,
65 | child: Text(status.toString()),
66 | ),
67 | ),
68 | SizedBox(height: 10),
69 | TextButton(
70 | onPressed: () async {
71 | final status = await showH5PayDialog(
72 | context: context,
73 | getPaymentArguments: () async => PaymentArguments(
74 | url: 'https://is.gd/4cLE6j',
75 | redirectSchemes: ['sms'],
76 | httpHeaders: {
77 | 'referer': 'https://is.gd',
78 | },
79 | ),
80 | verifyResult: () async => true,
81 | );
82 | ScaffoldMessenger.of(context).showSnackBar(SnackBar(
83 | content: Text(status.toString()),
84 | ));
85 | },
86 | child: Text('showH5PayDialog'),
87 | ),
88 | ],
89 | ),
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: h5pay_example
2 | description: Demonstrates how to use the h5pay plugin.
3 | publish_to: 'none'
4 |
5 | environment:
6 | sdk: ">=2.12.0 <3.0.0"
7 |
8 | dependencies:
9 | flutter:
10 | sdk: flutter
11 |
12 | # The following adds the Cupertino Icons font to your application.
13 | # Use with the CupertinoIcons class for iOS style icons.
14 | cupertino_icons: ^1.0.6
15 |
16 | dev_dependencies:
17 | flutter_test:
18 | sdk: flutter
19 |
20 | h5pay:
21 | path: ../
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.
27 | flutter:
28 |
29 | # The following line ensures that the Material Icons font is
30 | # included with your application, so that you can use the icons in
31 | # the material Icons class.
32 | uses-material-design: true
33 |
34 | # To add assets to your application, add an assets section, like this:
35 | # assets:
36 | # - images/a_dot_burr.jpeg
37 | # - images/a_dot_ham.jpeg
38 |
39 | # An image asset can refer to one or more resolution-specific "variants", see
40 | # https://flutter.dev/assets-and-images/#resolution-aware.
41 |
42 | # For details regarding adding assets from package dependencies, see
43 | # https://flutter.dev/assets-and-images/#from-packages
44 |
45 | # To add custom fonts to your application, add a fonts section here,
46 | # in this "flutter" section. Each entry in this list should have a
47 | # "family" key with the font family name, and a "fonts" key with a
48 | # list giving the asset and other descriptors for the font. For
49 | # example:
50 | # fonts:
51 | # - family: Schyler
52 | # fonts:
53 | # - asset: fonts/Schyler-Regular.ttf
54 | # - asset: fonts/Schyler-Italic.ttf
55 | # style: italic
56 | # - family: Trajan Pro
57 | # fonts:
58 | # - asset: fonts/TrajanPro.ttf
59 | # - asset: fonts/TrajanPro_Bold.ttf
60 | # weight: 700
61 | #
62 | # For details regarding fonts from package dependencies,
63 | # see https://flutter.dev/custom-fonts/#from-packages
64 |
--------------------------------------------------------------------------------
/image/screenshot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/image/screenshot.gif
--------------------------------------------------------------------------------
/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/flutter_export_environment.sh
--------------------------------------------------------------------------------
/ios/Assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nekocode/h5pay-flutter/0cee3173a0788d30899b045ca438408616ba0f68/ios/Assets/.gitkeep
--------------------------------------------------------------------------------
/ios/Classes/H5payPlugin.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface H5payPlugin : NSObject
4 | @end
5 |
--------------------------------------------------------------------------------
/ios/Classes/H5payPlugin.m:
--------------------------------------------------------------------------------
1 | #import "H5payPlugin.h"
2 | #import
3 |
4 | @implementation H5payPlugin
5 | + (void)registerWithRegistrar:(NSObject*)registrar {
6 | [SwiftH5payPlugin registerWithRegistrar:registrar];
7 | }
8 | @end
9 |
--------------------------------------------------------------------------------
/ios/Classes/SwiftH5payPlugin.swift:
--------------------------------------------------------------------------------
1 | import Flutter
2 | import UIKit
3 | import WebKit
4 |
5 | public class SwiftH5payPlugin: NSObject, FlutterPlugin {
6 | private var targetSchemes = [String]()
7 | private var httpHeaders = [String:String]()
8 | private var webView: WKWebView? = nil
9 | private var result: FlutterResult? = nil
10 |
11 | public static func register(with registrar: FlutterPluginRegistrar) {
12 | let channel = FlutterMethodChannel(name: "h5pay", binaryMessenger: registrar.messenger())
13 | let instance = SwiftH5payPlugin()
14 | registrar.addMethodCallDelegate(instance, channel: channel)
15 | }
16 |
17 | public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
18 | switch call.method {
19 | case "launchRedirectUrl":
20 | launchRedirectUrl(call, result: result)
21 | break
22 | case "launchUrl":
23 | launchUrl(call, result: result)
24 | break
25 | case "canLaunch":
26 | canLaunch(call, result: result)
27 | break
28 | default:
29 | result(FlutterMethodNotImplemented)
30 | break
31 | }
32 | }
33 |
34 | private func launchRedirectUrl(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
35 | guard
36 | let arguments = call.arguments as? [String: Any],
37 | let urlString = arguments["url"] as? String,
38 | let url = URL(string: urlString)
39 | else {
40 | result(false)
41 | return
42 | }
43 | if let targetSchemes = arguments["targetSchemes"] as? [String] {
44 | self.targetSchemes = targetSchemes
45 | } else {
46 | self.targetSchemes = [String]()
47 | }
48 | if let httpHeaders = arguments["httpHeaders"] as? [String:String] {
49 | self.httpHeaders = httpHeaders
50 | } else {
51 | self.httpHeaders = [String:String]()
52 | }
53 |
54 | // Try to launch url directly
55 | if (Utils.hasScheme(url, targetSchemes)) {
56 | result(Utils.launchUrl(url))
57 | return
58 | }
59 |
60 | initWebView()
61 | validateWebView()
62 |
63 | self.result = result
64 | var request = URLRequest.init(url: url)
65 | for (key, value) in self.httpHeaders {
66 | request.setValue(key, forHTTPHeaderField: value)
67 | }
68 | webView!.load(request)
69 | }
70 |
71 | private func launchUrl(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
72 | guard
73 | let arguments = call.arguments as? [String: Any],
74 | let urlString = arguments["url"] as? String,
75 | let url = URL(string: urlString)
76 | else {
77 | result(false)
78 | return
79 | }
80 | result(Utils.launchUrl(url))
81 | }
82 |
83 | private func canLaunch(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
84 | guard
85 | let arguments = call.arguments as? [String: Any],
86 | let urlString = arguments["url"] as? String,
87 | let url = URL(string: urlString)
88 | else {
89 | result(false)
90 | return
91 | }
92 | result(Utils.canLaunch(url))
93 | }
94 |
95 | private func initWebView() {
96 | if (webView != nil) {
97 | return
98 | }
99 |
100 | let config: WKWebViewConfiguration = WKWebViewConfiguration()
101 | if #available(iOS 9.0, *) {
102 | config.allowsPictureInPictureMediaPlayback = false
103 | config.requiresUserActionForMediaPlayback = true
104 | }
105 | if #available(iOS 10.0, *) {
106 | config.mediaTypesRequiringUserActionForPlayback = .all
107 | }
108 | config.allowsInlineMediaPlayback = true
109 |
110 | let preferences = WKPreferences()
111 | preferences.javaScriptEnabled = true
112 | config.preferences = preferences
113 |
114 | let webView = WKWebView(frame: .zero, configuration: config)
115 | webView.isHidden = true
116 | webView.navigationDelegate = self
117 | self.webView = webView
118 |
119 | validateWebView()
120 | }
121 |
122 | private func validateWebView() {
123 | if webView != nil && webView?.superview == nil {
124 | UIApplication.shared.keyWindow?.addSubview(webView!)
125 | }
126 | }
127 | }
128 |
129 | extension SwiftH5payPlugin: WKNavigationDelegate {
130 | public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
131 | decisionHandler(decidePolicyForRequest(navigationAction.request))
132 | }
133 |
134 | private func decidePolicyForRequest(_ request: URLRequest) -> WKNavigationActionPolicy {
135 | if let url = request.url {
136 | if (Utils.hasScheme(url, targetSchemes)) {
137 | result?(Utils.launchUrl(url))
138 | return .cancel
139 | }
140 | }
141 | return .allow
142 | }
143 | }
144 |
145 | class Utils {
146 | public static func launchUrl(_ url: URL) -> Bool {
147 | if !canLaunch(url) {
148 | return false
149 | } else {
150 | let success = UIApplication.shared.openURL(url)
151 | return success
152 | }
153 | }
154 |
155 | public static func canLaunch(_ url: URL) -> Bool {
156 | return UIApplication.shared.canOpenURL(url)
157 | }
158 |
159 | public static func hasScheme(_ url: URL, _ targetSchemes: [String]) -> Bool {
160 | let urlString = url.absoluteString
161 | for scheme in targetSchemes {
162 | if !urlString.hasPrefix(scheme + ":") {
163 | continue
164 | }
165 | return true
166 | }
167 | return false
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/ios/h5pay.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
3 | # Run `pod lib lint h5pay.podspec' to validate before publishing.
4 | #
5 | Pod::Spec.new do |s|
6 | s.name = 'h5pay'
7 | s.version = '0.0.1'
8 | s.summary = 'A new flutter plugin project.'
9 | s.description = <<-DESC
10 | A new flutter plugin project.
11 | DESC
12 | s.homepage = 'http://example.com'
13 | s.license = { :file => '../LICENSE' }
14 | s.author = { 'Your Company' => 'email@example.com' }
15 | s.source = { :path => '.' }
16 | s.source_files = 'Classes/**/*'
17 | s.public_header_files = 'Classes/**/*.h'
18 | s.dependency 'Flutter'
19 | s.platform = :ios, '8.0'
20 |
21 | # Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
22 | s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
23 | end
24 |
--------------------------------------------------------------------------------
/lib/h5pay.dart:
--------------------------------------------------------------------------------
1 | export 'src/h5pay_channel.dart';
2 | export 'src/h5pay_dialog.dart';
3 | export 'src/h5pay_widget.dart';
4 |
--------------------------------------------------------------------------------
/lib/src/h5pay_channel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class H5PayChannel {
4 | static const _channel = const MethodChannel('h5pay');
5 |
6 | static Future launchRedirectUrl(
7 | String url,
8 | List targetSchemes, {
9 | Map? httpHeaders,
10 | }) {
11 | print(httpHeaders);
12 | return _channel.invokeMethod(
13 | 'launchRedirectUrl',
14 | {
15 | 'url': url,
16 | 'targetSchemes': targetSchemes,
17 | 'httpHeaders': httpHeaders,
18 | },
19 | );
20 | }
21 |
22 | static Future launchUrl(String url) {
23 | return _channel.invokeMethod(
24 | 'launchUrl',
25 | {
26 | 'url': url,
27 | },
28 | );
29 | }
30 |
31 | static Future canLaunch(String url) {
32 | return _channel.invokeMethod(
33 | 'canLaunch',
34 | {
35 | 'url': url,
36 | },
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/h5pay_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | import 'h5pay_widget.dart';
6 |
7 | Future showH5PayDialog({
8 | required BuildContext context,
9 | required GetArgumentsCallback getPaymentArguments,
10 | VerifyResultCallback? verifyResult,
11 | WidgetBuilder? builder,
12 | }) {
13 | return showGeneralDialog(
14 | context: context,
15 | barrierDismissible: false,
16 | barrierColor: Colors.black54,
17 | transitionDuration: const Duration(milliseconds: 150),
18 | pageBuilder: (
19 | BuildContext buildContext,
20 | Animation animation,
21 | Animation secondaryAnimation,
22 | ) {
23 | return WillPopScope(
24 | onWillPop: () async => false,
25 | child: SafeArea(
26 | child: Builder(builder: (BuildContext context) {
27 | return _H5PayDialog(
28 | getPaymentArguments: getPaymentArguments,
29 | verifyResult: verifyResult,
30 | builder: builder,
31 | );
32 | }),
33 | ),
34 | );
35 | },
36 | );
37 | }
38 |
39 | class _H5PayDialog extends StatelessWidget {
40 | _H5PayDialog({
41 | Key? key,
42 | required this.getPaymentArguments,
43 | this.verifyResult,
44 | WidgetBuilder? builder,
45 | }) : this.builder = builder ?? _buildSimpleDialog,
46 | super(key: key);
47 |
48 | final GetArgumentsCallback getPaymentArguments;
49 | final VerifyResultCallback? verifyResult;
50 | final WidgetBuilder builder;
51 |
52 | @override
53 | Widget build(BuildContext context) {
54 | return H5PayWidget(
55 | getPaymentArguments: getPaymentArguments,
56 | verifyResult: verifyResult,
57 | builder: (context, status, controller) {
58 | switch (status) {
59 | case PaymentStatus.idle:
60 | controller.launch();
61 | break;
62 | case PaymentStatus.gettingArguments:
63 | case PaymentStatus.launchingUrl:
64 | case PaymentStatus.jumping:
65 | case PaymentStatus.verifying:
66 | break;
67 | case PaymentStatus.getArgumentsFail:
68 | case PaymentStatus.cantLaunchUrl:
69 | case PaymentStatus.launchUrlTimeout:
70 | case PaymentStatus.jumpTimeout:
71 | case PaymentStatus.success:
72 | case PaymentStatus.fail:
73 | // Pop dialog with result
74 | Future.microtask(() {
75 | Navigator.pop(context, status);
76 | });
77 | break;
78 | }
79 |
80 | return builder(context);
81 | },
82 | );
83 | }
84 |
85 | static Widget _buildSimpleDialog(BuildContext context) {
86 | return Center(
87 | child: Container(
88 | width: 80,
89 | height: 80,
90 | decoration: BoxDecoration(
91 | color: const Color(0xFFFFFFFF),
92 | borderRadius: BorderRadius.circular(10),
93 | ),
94 | child: const Center(child: CupertinoActivityIndicator()),
95 | ),
96 | );
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/lib/src/h5pay_widget.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/widgets.dart';
4 |
5 | import 'h5pay_channel.dart';
6 | import 'utils.dart';
7 |
8 | enum PaymentStatus {
9 | idle,
10 | gettingArguments,
11 | getArgumentsFail,
12 | launchingUrl,
13 | cantLaunchUrl, // Maybe target payment app is not installed
14 | launchUrlTimeout, // Maybe redirecting url is fail
15 | jumping,
16 | jumpTimeout,
17 | verifying,
18 | success,
19 | fail,
20 | }
21 |
22 | class PaymentArguments {
23 | // Payment url (can be http or any other protocol)
24 | final String url;
25 |
26 | // If scheme of the 'url' argument is 'http' and this argument is not null,
27 | // then this library will launch the url in a hidden webview, catch the
28 | // redirect url which has the scheme you specified, and finally launch
29 | // the new url by using the system api.
30 | //
31 | // You can leave this argument to null to launch the url by using
32 | // the system api directly.
33 | final List? redirectSchemes;
34 |
35 | // Additional http headers for webview
36 | final Map? httpHeaders;
37 |
38 | // Timeout duration of jumping to payment app (or system browser)
39 | final Duration jumpTimeout;
40 |
41 | // Timeout duration of launching url
42 | final Duration launchUrlTimeout;
43 |
44 | PaymentArguments({
45 | required this.url,
46 | this.redirectSchemes,
47 | this.httpHeaders,
48 | Duration? jumpTimeout,
49 | Duration? launchUrlTimeout,
50 | }) : assert(url.isNotEmpty),
51 | assert(jumpTimeout == null || !jumpTimeout.isNegative),
52 | assert(launchUrlTimeout == null || !launchUrlTimeout.isNegative),
53 | this.jumpTimeout = jumpTimeout ?? const Duration(seconds: 3),
54 | this.launchUrlTimeout = launchUrlTimeout ?? const Duration(seconds: 5);
55 | }
56 |
57 | typedef Future GetArgumentsCallback();
58 | typedef Future VerifyResultCallback();
59 | typedef Widget H5PayWidgetBuilder(
60 | BuildContext context,
61 | PaymentStatus status,
62 | H5PayController controller,
63 | );
64 |
65 | class H5PayController {
66 | final _launchNotifier = SimpleChangeNotifier();
67 |
68 | void launch() {
69 | _launchNotifier.notify();
70 | }
71 |
72 | void _dispose() {
73 | _launchNotifier.dispose();
74 | }
75 | }
76 |
77 | class H5PayWidget extends StatefulWidget {
78 | const H5PayWidget({
79 | Key? key,
80 | required this.getPaymentArguments,
81 | required this.builder,
82 | this.verifyResult,
83 | }) : super(key: key);
84 |
85 | final GetArgumentsCallback getPaymentArguments;
86 | final VerifyResultCallback? verifyResult;
87 | final H5PayWidgetBuilder builder;
88 |
89 | @override
90 | _H5PayWidgetState createState() => _H5PayWidgetState();
91 | }
92 |
93 | class _H5PayWidgetState extends State with WidgetsBindingObserver {
94 | static const _checkJumpPeriod = Duration(milliseconds: 100);
95 | final _controller = H5PayController();
96 |
97 | PaymentStatus _status = PaymentStatus.idle;
98 | bool _listenLifecycle = false;
99 | bool _jumped = false;
100 |
101 | @override
102 | void initState() {
103 | super.initState();
104 | WidgetsBinding.instance?.addObserver(this);
105 | _controller._launchNotifier.addListener(() async {
106 | // Start to get payment arguments
107 | _setPaymentStatus(PaymentStatus.gettingArguments);
108 | PaymentArguments args;
109 | try {
110 | args = await widget.getPaymentArguments();
111 | } catch (_) {
112 | _setPaymentStatus(PaymentStatus.getArgumentsFail);
113 | return;
114 | }
115 | if (!mounted) {
116 | return;
117 | }
118 |
119 | // Start to launch url
120 | _setPaymentStatus(PaymentStatus.launchingUrl);
121 | var failStatus = await _launch(args);
122 | if (!mounted) {
123 | return;
124 | }
125 | if (failStatus != null) {
126 | _setPaymentStatus(failStatus);
127 | return;
128 | }
129 |
130 | // Start to listen app lifecycle
131 | _listenLifecycle = true;
132 | _jumped = false;
133 | _setPaymentStatus(PaymentStatus.jumping);
134 |
135 | // Check if jump is successful
136 | failStatus = await _checkJump(args);
137 | if (!mounted) {
138 | return;
139 | }
140 | if (failStatus != null) {
141 | // Jump failed
142 | _listenLifecycle = false;
143 | _setPaymentStatus(failStatus);
144 | return;
145 | }
146 | });
147 | }
148 |
149 | @override
150 | void dispose() {
151 | _controller._dispose();
152 | WidgetsBinding.instance?.removeObserver(this);
153 | super.dispose();
154 | }
155 |
156 | @override
157 | void didChangeAppLifecycleState(AppLifecycleState state) async {
158 | if (!_listenLifecycle) {
159 | return;
160 | }
161 |
162 | if (state == AppLifecycleState.inactive) {
163 | // Start to jump to payment app
164 | _jumped = true;
165 | } else if (state == AppLifecycleState.resumed) {
166 | // Resume from payment app
167 | _listenLifecycle = false;
168 |
169 | bool success = true;
170 | // Try to verify the payment result
171 | final verifyResult = widget.verifyResult;
172 | if (verifyResult != null) {
173 | _setPaymentStatus(PaymentStatus.verifying);
174 | try {
175 | success = await verifyResult();
176 | } catch (_) {
177 | success = false;
178 | }
179 | }
180 |
181 | _setPaymentStatus(
182 | success == true ? PaymentStatus.success : PaymentStatus.fail);
183 | }
184 | }
185 |
186 | Future _launch(PaymentArguments args) async {
187 | final completer = Completer();
188 | void completeOnce(PaymentStatus? status) {
189 | if (!completer.isCompleted) {
190 | completer.complete(status);
191 | }
192 | }
193 |
194 | final redirectSchemes = args.redirectSchemes;
195 | if (redirectSchemes != null) {
196 | H5PayChannel.launchRedirectUrl(
197 | args.url,
198 | redirectSchemes,
199 | httpHeaders: args.httpHeaders,
200 | ).then((success) {
201 | if (success == true) {
202 | completeOnce(null);
203 | } else {
204 | completeOnce(PaymentStatus.cantLaunchUrl);
205 | }
206 | }).catchError((e) {
207 | debugPrint(e.toString());
208 | completeOnce(PaymentStatus.fail);
209 | });
210 | } else {
211 | H5PayChannel.launchUrl(args.url).then((success) {
212 | if (success == true) {
213 | completeOnce(null);
214 | } else {
215 | completeOnce(PaymentStatus.cantLaunchUrl);
216 | }
217 | }).catchError((e) {
218 | debugPrint(e.toString());
219 | completeOnce(PaymentStatus.fail);
220 | });
221 | }
222 |
223 | Future.delayed(args.launchUrlTimeout, () {
224 | completeOnce(PaymentStatus.launchUrlTimeout);
225 | });
226 |
227 | return completer.future;
228 | }
229 |
230 | Future _checkJump(PaymentArguments args) async {
231 | final count =
232 | (args.jumpTimeout.inMilliseconds / _checkJumpPeriod.inMilliseconds)
233 | .ceil();
234 |
235 | // Cycle check
236 | for (int i = 0; i < count; i++) {
237 | if (_jumped || !mounted) {
238 | return null;
239 | }
240 | await Future.delayed(_checkJumpPeriod);
241 | }
242 |
243 | return PaymentStatus.jumpTimeout;
244 | }
245 |
246 | void _setPaymentStatus(PaymentStatus status) {
247 | _status = status;
248 | if (mounted) {
249 | setState(() {});
250 | }
251 | }
252 |
253 | @override
254 | Widget build(BuildContext context) {
255 | return widget.builder(context, _status, _controller);
256 | }
257 | }
258 |
--------------------------------------------------------------------------------
/lib/src/utils.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 |
3 | class SimpleChangeNotifier extends ChangeNotifier {
4 | void notify() {
5 | notifyListeners();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: h5pay
2 | description: An H5/HTML5 payment (such as Alipay, WeChat Pay) plugin for flutter.
3 | version: 1.1.1
4 | homepage: https://github.com/nekocode/h5pay-flutter
5 |
6 | flutter:
7 | plugin:
8 | platforms:
9 | android:
10 | package: cn.nekocode.h5pay
11 | pluginClass: H5payPlugin
12 | ios:
13 | pluginClass: H5payPlugin
14 |
15 | environment:
16 | sdk: ">=2.12.0 <3.0.0"
17 | flutter: ">=1.12.0"
18 |
19 | dependencies:
20 | flutter:
21 | sdk: flutter
22 |
23 | dev_dependencies:
24 | flutter_test:
25 | sdk: flutter
26 |
27 |
--------------------------------------------------------------------------------
/test/h5pay_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/services.dart';
3 | import 'package:flutter_test/flutter_test.dart';
4 | import 'package:h5pay/h5pay.dart';
5 |
6 | void main() {
7 | const MethodChannel channel = MethodChannel('h5pay');
8 |
9 | TestWidgetsFlutterBinding.ensureInitialized();
10 |
11 | setUp(() {
12 | channel.setMockMethodCallHandler((MethodCall methodCall) async {
13 | expect(methodCall.method, 'launchRedirectUrl');
14 | await Future.delayed(Duration(milliseconds: 500));
15 | return true;
16 | });
17 | });
18 |
19 | tearDown(() {
20 | channel.setMockMethodCallHandler(null);
21 | });
22 |
23 | testWidgets('H5PayWidget test', (WidgetTester tester) async {
24 | await tester.pumpWidget(
25 | MaterialApp(
26 | home: Scaffold(
27 | body: H5PayWidget(
28 | getPaymentArguments: () async => Future.delayed(
29 | Duration(milliseconds: 500),
30 | () => PaymentArguments(
31 | url: 'https://baidu.com',
32 | redirectSchemes: ['sms'],
33 | ),
34 | ),
35 | verifyResult: () async =>
36 | Future.delayed(Duration(milliseconds: 500), () => true),
37 | builder: (context, status, controller) {
38 | print('Current payment status: ' + status.toString());
39 | return TextButton(
40 | onPressed: controller.launch,
41 | child: Text(status.toString()),
42 | );
43 | },
44 | ),
45 | ),
46 | ),
47 | );
48 |
49 | Finder findText(PaymentStatus status) => find.text(status.toString());
50 | void verifyStatus(PaymentStatus status) {
51 | expect(findText(status), findsOneWidget);
52 | }
53 |
54 | Future changeAppLifecycleState(AppLifecycleState state) async {
55 | return ServicesBinding.instance?.defaultBinaryMessenger
56 | .handlePlatformMessage(
57 | 'flutter/lifecycle',
58 | const StringCodec().encodeMessage(state.toString()),
59 | (_) {},
60 | );
61 | }
62 |
63 | verifyStatus(PaymentStatus.idle);
64 | await tester.tap(findText(PaymentStatus.idle));
65 | await tester.pump();
66 | verifyStatus(PaymentStatus.gettingArguments);
67 | await tester.pump(new Duration(milliseconds: 600));
68 | verifyStatus(PaymentStatus.launchingUrl);
69 | await tester.pump(new Duration(milliseconds: 600));
70 | verifyStatus(PaymentStatus.jumping);
71 |
72 | await changeAppLifecycleState(AppLifecycleState.inactive);
73 | await tester.pump();
74 | await changeAppLifecycleState(AppLifecycleState.resumed);
75 | await tester.pump();
76 |
77 | verifyStatus(PaymentStatus.verifying);
78 | await tester.pump(new Duration(milliseconds: 600));
79 | verifyStatus(PaymentStatus.success);
80 | await tester.pump(new Duration(milliseconds: 5000));
81 | });
82 | }
83 |
--------------------------------------------------------------------------------