提交 437ecd40 authored 作者: JarvanMo's avatar JarvanMo

Merge remote-tracking branch 'origin/v4'

...@@ -16,14 +16,14 @@ RUN sudo apt-get update && sudo apt-get install -y google-cloud-sdk && \ ...@@ -16,14 +16,14 @@ RUN sudo apt-get update && sudo apt-get install -y google-cloud-sdk && \
gcloud config set component_manager/disable_update_check true gcloud config set component_manager/disable_update_check true
RUN yes | sdkmanager \ RUN yes | sdkmanager \
"platforms;android-29" \ "platforms;android-33" \
"build-tools;29.0.2" \ "build-tools;33.0.2" \
"extras;google;m2repository" \ "extras;google;m2repository" \
"extras;android;m2repository" "extras;android;m2repository"
RUN yes | sdkmanager \ RUN yes | sdkmanager \
"platforms;android-30" \ "platforms;android-32" \
"build-tools;28.0.3" \ "build-tools;33.0.2" \
"extras;google;m2repository" \ "extras;google;m2repository" \
"extras;android;m2repository" "extras;android;m2repository"
......
...@@ -37,3 +37,4 @@ example/.pub-cache/ ...@@ -37,3 +37,4 @@ example/.pub-cache/
example/.pub/ example/.pub/
example/build/ example/build/
example example
example/android/app/debug.keystore
# 4.0.0
* 重构Flutter端,现在需要`Fluwx fluwx = Fluwx();`调用fluwx实例
* 支持取消回传值的监听
* 枚举例按照dart语言规范进行了重命名
* 一些包含`WeChat`的方法删除了`WeChat`
* 部分类改为sealed class
* No_pay现已合并入Fluwx
* 将一些设置移到pubspec.yaml,具体可以参看`example/pubspec.yaml`
* 删除了log相关操作,因为现在可以通过yaml配置
* 新增一些open功能
# 4.0.0-pre.3
* `Fluwx`接口优化。合并了一些函数以优化使用体验。
* 修复Logging在iOS端不好的问题。
# 4.0.0-pre.2
* No_pay现已合并入Fluwx
* 将一些设置移到pubspec.yaml,具体可以参看`example/pubspec.yaml`
* 删除了log相关操作,因为现在可以通过yaml配置
* 增加了open()方法并删除了openWeChatApp
# 4.0.0-pre.1
* 重构Flutter端,现在需要`Fluwx fluwx = Fluwx();`调用fluwx实例
* 支持取消回传值的监听
* 枚举例按照dart语言规范进行了重命名
* 一些包含`WeChat`的方法删除了`WeChat`
* 部分类改为sealed class
* 最低dart版本>=3.1.0-26.0.dev
# 3.13.1 # 3.13.1
* 分享到小程序的thumbnail为必填 * 分享到小程序的thumbnail为必填
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
## Preparation ## Preparation
[Migrate to V4 now](./doc/MIGRATE_TO_V4_CN.md)
`Fluwx` is good but not God. You'd better read [official documents](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1) before `Fluwx` is good but not God. You'd better read [official documents](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1) before
integrating `Fluwx`. Then you'll understand how to generate Android signature, what's universal link for iOS, how to add URL schema for iOS and so on. integrating `Fluwx`. Then you'll understand how to generate Android signature, what's universal link for iOS, how to add URL schema for iOS and so on.
...@@ -49,23 +51,34 @@ dependencies: ...@@ -49,23 +51,34 @@ dependencies:
`Fluwx` without pay: `Fluwx` without pay:
```yaml > Developers who need to exclude payment for iOS can enable `no_pay` in [pubspec.yaml](./example/pubspec.yaml).
dependencies:
fluwx_no_pay: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg) ![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)
> NOTE: Never forget to replace ^${latestVersion} with actual version. > NOTE: Never forget to replace ^${latestVersion} with actual version.
## Configurations
`Fluwx` enables multiple configurations in the section `fluwx` of `pubspec.yaml` from v4, you can reference [pubspec.yaml](./example/pubspec.yaml)
for more details.
> For iOS, some configurations, such as url_scheme,universal_link, LSApplicationQueriesSchemes, can be configured by `fluwx`,
> what you need to do is to fill configurations in `pubspec.yaml`
- app_id. Required. It'll be used to generate scheme on iOS and register WxApi on Android side if app is cold boot.
- debug_logging. Optional. Enable logs by setting it `true`.
- flutter_activity. Optional. This is usually used by cold boot from WeChat on Android. `Fluwx` will try to launch launcher activity if not set.
- universal_link. Required for iOS. It'll be used to generate universal link on your projects.
## Register WxAPI ## Register WxAPI
Register your app via `fluwx` if necessary. Register your app via `fluwx` if necessary.
```dart ```dart
registerWxApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/"); Fluwx fluwx = Fluwx();
fluwx.registerApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/");
``` ```
The param `universalLink` only works with iOS. You can read [this document](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) to learn The param `universalLink` only works with iOS. You can read [this document](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) to learn
how to create universalLink. You can also learn how to add URL schema, how to add `LSApplicationQueriesSchemes` in your iOS project. This is essential. how to create universalLink. You can also learn how to add URL schema, how to add `LSApplicationQueriesSchemes` in your iOS project. This is essential.
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
## 准备 ## 准备
[迁移到V4指南](./doc/MIGRATE_TO_V4_CN.md)
`Fluwx` 可以做很多工作但不是所有. 在集成之前,最好读一下[官方文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1). `Fluwx` 可以做很多工作但不是所有. 在集成之前,最好读一下[官方文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1).
然后你才知道怎么生成签名,怎么使用universal link以及怎么添加URL schema等. 然后你才知道怎么生成签名,怎么使用universal link以及怎么添加URL schema等.
...@@ -46,23 +48,32 @@ dependencies: ...@@ -46,23 +48,32 @@ dependencies:
``` ```
![pub package](https://img.shields.io/pub/v/fluwx.svg) ![pub package](https://img.shields.io/pub/v/fluwx.svg)
`Fluwx`,不带支付: 不带支付的`Fluwx`:
```yaml
dependencies:
fluwx_no_pay: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg) > 一些开发者并不需要在iOS端使用支付能力,此时您可以通过在[pubspec.yaml](./example/pubspec.yaml).
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)中开启`no_pay`
> NOTE: 别忘记替换 ^${latestVersion} !!!! > NOTE: 别忘记替换 ^${latestVersion} !!!!
## 配置
`Fluwx` 从v4开始可以在`pubspec.yaml``fluwx`进行一些配置。具体可以参考[pubspec.yaml](./example/pubspec.yaml)
> V4开始,iOS中的url_scheme,universal_link, LSApplicationQueriesSchemes可以不必开发者手动配动。只需在`pubspec.yaml`
> 中填写即可。
- app_id. 必填. 它将用于生成iOS的url_scheme以及在Android端冷启动时,重新初始化WxApi。
- debug_logging. 可选. 把它设置成`true`可以开启日志。
- flutter_activity. 可选. 这个通常是用于Android的冷启动。如果不设置任何值,`Fluwx`将尝试启动launcher activity.
- universal_link. iOS 必填. 它将用自动配置universal_link。
## 注册 WxAPI ## 注册 WxAPI
通过 `fluwx` 注册WxApi. 通过 `fluwx` 注册WxApi.
```dart ```dart
registerWxApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/"); Fluwx fluwx = Fluwx();
fluwx.registerApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/");
``` ```
参数 `universalLink` 只在iOS上有用. 查看[文档](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) 以便了解如何生成通用链接. 参数 `universalLink` 只在iOS上有用. 查看[文档](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) 以便了解如何生成通用链接.
......
include: package:flutter_lints/flutter.yaml
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
...@@ -6,3 +6,4 @@ ...@@ -6,3 +6,4 @@
.DS_Store .DS_Store
/build /build
/captures /captures
.cxx
import org.yaml.snakeyaml.Yaml
group 'com.jarvan.fluwx' group 'com.jarvan.fluwx'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
...@@ -9,12 +11,13 @@ buildscript { ...@@ -9,12 +11,13 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.yaml:snakeyaml:2.0"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
rootProject.allprojects { allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
...@@ -23,28 +26,77 @@ rootProject.allprojects { ...@@ -23,28 +26,77 @@ rootProject.allprojects {
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 31 namespace "com.jarvan.fluwx"
compileSdk 31
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
test.java.srcDirs += 'src/test/kotlin'
} }
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
consumerProguardFiles 'consumer-proguard-rules.txt' consumerProguardFiles 'consumer-proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" manifestPlaceholders = loadManifestPlaceholder()
} }
lintOptions {
disable 'InvalidPackage'
}
}
dependencies { dependencies {
api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.24' api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.24'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'id.zelory:compressor:3.0.1' implementation 'id.zelory:compressor:3.0.1'
implementation 'com.squareup.okhttp3:okhttp:4.9.1' implementation 'com.squareup.okhttp3:okhttp:4.10.0'
testImplementation 'junit:junit:4.13.2' testImplementation 'org.jetbrains.kotlin:kotlin-test'
testImplementation 'org.mockito:mockito-core:5.0.0'
}
testOptions {
unitTests.all {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen { false }
showStandardStreams = true
}
}
}
}
Map loadManifestPlaceholder() {
def path = rootProject.projectDir.parent + File.separator + "pubspec.yaml"
InputStream input = new FileInputStream(new File(path))
Yaml yaml = new Yaml()
Map projectConfig = yaml.load(input)
String appId = ""
String interruptWxRequest = "true"
String flutterActivity = ""
String debugLogging = "disabled"
Map fluwx = (Map) projectConfig.get("fluwx")
if (fluwx) {
Map android = (Map) fluwx.get("android")
if (android) {
def iwr = android.get("interrupt_wx_request")
if (iwr) {
interruptWxRequest = (String) iwr
}
def activity = android.get("flutter_activity")
if (activity) {
flutterActivity = (String) activity
}
}
def logging = fluwx.get("debug_logging")
if (logging && logging == "true") {
debugLogging = "true"
}
}
return ["WeChatAppId": appId,
"InterruptWeChatRequestByFluwx": interruptWxRequest,
"FluwxFlutterActivity": flutterActivity,
"WeChatDebugLogging": debugLogging]
} }
group = "com.jarvan.fluwx"
version = "1.0-SNAPSHOT"
plugins {
id("com.android.library")
kotlin("android")
}
allprojects {
repositories {
google()
mavenCentral()
}
}
android {
namespace = "com.jarvan.fluwx"
compileSdk = 31
sourceSets {
val main by getting
main.java.srcDirs("src/main/kotlin")
val test by getting
test.java.srcDirs("src/test/kotlin")
}
defaultConfig {
minSdk = 16
consumerProguardFile("consumer-proguard-rules.txt")
}
testOptions {
unitTests.all {
it.useJUnitPlatform()
it.testLogging {
events("passed", "skipped", "failed", "standardOut", "standardError")
showStandardStreams = true
it.outputs.upToDateWhen {
false
}
}
}
}
}
dependencies {
api("com.tencent.mm.opensdk:wechat-sdk-android:6.8.24")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
implementation("id.zelory:compressor:3.0.1")
implementation("com.squareup.okhttp3:okhttp:4.10.0")
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.mockito:mockito-core:5.0.0")
}
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.jarvan.fluwx">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
...@@ -12,10 +11,26 @@ ...@@ -12,10 +11,26 @@
</queries> </queries>
<application> <application>
<meta-data
android:name="WeChatAppId"
android:value="${WeChatAppId}" />
<meta-data
android:name="InterruptWeChatRequestByFluwx"
android:value="${InterruptWeChatRequestByFluwx}" />
<meta-data
android:name="WeChatDebugLogging"
android:value="${WeChatDebugLogging}" />
<meta-data
android:name="FluwxFlutterActivity"
android:value="${FluwxFlutterActivity}" />
<activity <activity
android:name=".wxapi.FluwxWXEntryActivity" android:name=".wxapi.FluwxWXEntryActivity"
android:launchMode="singleTask"
android:exported="false" android:exported="false"
android:launchMode="singleTask"
android:taskAffinity="${applicationId}" android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" /> android:theme="@style/DisablePreviewTheme" />
...@@ -25,13 +40,14 @@ ...@@ -25,13 +40,14 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity" android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="${applicationId}" android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme"/> android:theme="@style/DisablePreviewTheme" />
<activity-alias <activity-alias
android:name="${applicationId}.wxapi.WXPayEntryActivity" android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true" android:exported="true"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity" android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme"/> android:theme="@style/DisablePreviewTheme" />
<provider <provider
android:name="com.jarvan.fluwx.FluwxFileProvider" android:name="com.jarvan.fluwx.FluwxFileProvider"
......
...@@ -2,12 +2,25 @@ package com.jarvan.fluwx ...@@ -2,12 +2,25 @@ package com.jarvan.fluwx
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log
import androidx.annotation.NonNull import androidx.annotation.NonNull
import com.jarvan.fluwx.handlers.* import com.jarvan.fluwx.handlers.FluwxAuthHandler
import com.jarvan.fluwx.handlers.FluwxRequestHandler
import com.jarvan.fluwx.handlers.FluwxShareHandler
import com.jarvan.fluwx.handlers.FluwxShareHandlerEmbedding
import com.jarvan.fluwx.handlers.PermissionHandler
import com.jarvan.fluwx.handlers.WXAPiHandler
import com.jarvan.fluwx.utils.KEY_FLUWX_REQUEST_INFO_EXT_MSG
import com.jarvan.fluwx.utils.WXApiUtils import com.jarvan.fluwx.utils.WXApiUtils
import com.tencent.mm.opensdk.modelbiz.* import com.tencent.mm.opensdk.modelbiz.ChooseCardFromWXCardPackage
import com.tencent.mm.opensdk.modelbiz.OpenRankList
import com.tencent.mm.opensdk.modelbiz.OpenWebview
import com.tencent.mm.opensdk.modelbiz.SubscribeMessage
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessView
import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessWebview
import com.tencent.mm.opensdk.modelbiz.WXOpenCustomerServiceChat
import com.tencent.mm.opensdk.modelpay.PayReq import com.tencent.mm.opensdk.modelpay.PayReq
import com.tencent.mm.opensdk.openapi.SendReqCallback
import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
...@@ -36,31 +49,27 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ...@@ -36,31 +49,27 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
private var context: Context? = null private var context: Context? = null
private fun handelIntent(intent: Intent) { private fun handelIntent(intent: Intent) {
val action = intent.action intent.getStringExtra(KEY_FLUWX_REQUEST_INFO_EXT_MSG)?.let {
val dataString = intent.dataString extMsg = it
if (Intent.ACTION_VIEW == action) {
extMsg = dataString
} }
} }
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.jarvanmo/fluwx") val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.jarvanmo/fluwx")
channel.setMethodCallHandler(this) channel.setMethodCallHandler(this)
val applicationContext = flutterPluginBinding.applicationContext
fluwxChannel = channel fluwxChannel = channel
context = flutterPluginBinding.applicationContext context = flutterPluginBinding.applicationContext
authHandler = FluwxAuthHandler(channel) authHandler = FluwxAuthHandler(channel)
shareHandler = FluwxShareHandlerEmbedding( shareHandler = FluwxShareHandlerEmbedding(
flutterPluginBinding.flutterAssets, flutterPluginBinding.flutterAssets, flutterPluginBinding.applicationContext
flutterPluginBinding.applicationContext
) )
} }
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) { override fun onMethodCall(call: MethodCall, result: Result) {
callingChannel = fluwxChannel callingChannel = fluwxChannel
when { when {
call.method == "registerApp" -> WXAPiHandler.registerApp(call, result, context) call.method == "registerApp" -> WXAPiHandler.registerApp(call, result, context)
call.method == "startLog" -> WXAPiHandler.startLog(call, result)
call.method == "stopLog" -> WXAPiHandler.stopLog(call, result)
call.method == "sendAuth" -> authHandler?.sendAuth(call, result) call.method == "sendAuth" -> authHandler?.sendAuth(call, result)
call.method == "authByQRCode" -> authHandler?.authByQRCode(call, result) call.method == "authByQRCode" -> authHandler?.authByQRCode(call, result)
call.method == "stopAuthByQRCode" -> authHandler?.stopAuthByQRCode(result) call.method == "stopAuthByQRCode" -> authHandler?.stopAuthByQRCode(result)
...@@ -75,15 +84,18 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ...@@ -75,15 +84,18 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
call.method == "isWeChatInstalled" -> WXAPiHandler.checkWeChatInstallation(result) call.method == "isWeChatInstalled" -> WXAPiHandler.checkWeChatInstallation(result)
call.method == "getExtMsg" -> getExtMsg(result) call.method == "getExtMsg" -> getExtMsg(result)
call.method == "openWeChatCustomerServiceChat" -> openWeChatCustomerServiceChat( call.method == "openWeChatCustomerServiceChat" -> openWeChatCustomerServiceChat(
call, call, result
result
) )
call.method == "checkSupportOpenBusinessView" -> WXAPiHandler.checkSupportOpenBusinessView( call.method == "checkSupportOpenBusinessView" -> WXAPiHandler.checkSupportOpenBusinessView(
result result
) )
call.method == "openBusinessView" -> openBusinessView(call, result) call.method == "openBusinessView" -> openBusinessView(call, result)
call.method == "openWeChatInvoice" -> openWeChatInvoice(call, result); call.method == "openWeChatInvoice" -> openWeChatInvoice(call, result)
call.method == "openUrl" -> openUrl(call, result)
call.method == "openRankList" -> openRankList(result)
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
...@@ -104,7 +116,9 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ...@@ -104,7 +116,9 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
request.timeStamp = System.currentTimeMillis().toString() request.timeStamp = System.currentTimeMillis().toString()
request.nonceStr = System.currentTimeMillis().toString() request.nonceStr = System.currentTimeMillis().toString()
request.signType = "SHA1" request.signType = "SHA1"
request.cardSign = WXApiUtils.createSign(request.appId, request.nonceStr, request.timeStamp, request.cardType) request.cardSign = WXApiUtils.createSign(
request.appId, request.nonceStr, request.timeStamp, request.cardType
)
val done = WXAPiHandler.wxApi?.sendReq(request) val done = WXAPiHandler.wxApi?.sendReq(request)
result.success(done) result.success(done)
} }
...@@ -122,11 +136,13 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ...@@ -122,11 +136,13 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) { override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
shareHandler?.permissionHandler = PermissionHandler(binding.activity) shareHandler?.permissionHandler = PermissionHandler(binding.activity)
handelIntent(binding.activity.intent) handelIntent(binding.activity.intent)
FluwxRequestHandler.handleRequestInfoFromIntent(binding.activity.intent)
} }
override fun onAttachedToActivity(binding: ActivityPluginBinding) { override fun onAttachedToActivity(binding: ActivityPluginBinding) {
// WXAPiHandler.setContext(binding.activity.applicationContext) // WXAPiHandler.setContext(binding.activity.applicationContext)
handelIntent(binding.activity.intent) handelIntent(binding.activity.intent)
FluwxRequestHandler.handleRequestInfoFromIntent(binding.activity.intent)
shareHandler?.permissionHandler = PermissionHandler(binding.activity) shareHandler?.permissionHandler = PermissionHandler(binding.activity)
} }
...@@ -262,8 +278,27 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware, ...@@ -262,8 +278,27 @@ class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
private fun openWXApp(result: Result) = result.success(WXAPiHandler.wxApi?.openWXApp()) private fun openWXApp(result: Result) = result.success(WXAPiHandler.wxApi?.openWXApp())
private fun openUrl(call: MethodCall, result: Result) {
val req = OpenWebview.Req()
req.url = call.argument("url")
WXAPiHandler.wxApi?.sendReq(req, SendReqCallback {
result.success(it)
}) ?: kotlin.run {
result.success(false)
}
}
private fun openRankList(result: Result) {
val req = OpenRankList.Req()
WXAPiHandler.wxApi?.sendReq(req, SendReqCallback {
result.success(it)
}) ?: kotlin.run {
result.success(false)
}
}
override fun onNewIntent(intent: Intent): Boolean { override fun onNewIntent(intent: Intent): Boolean {
handelIntent(intent) handelIntent(intent)
return false return false
} }
} }
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package com.jarvan.fluwx.handlers package com.jarvan.fluwx.handlers
import android.app.Activity import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
...@@ -24,13 +25,15 @@ import android.os.Bundle ...@@ -24,13 +25,15 @@ import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.core.content.ContextCompat.startActivity import androidx.core.content.ContextCompat.startActivity
import com.jarvan.fluwx.FluwxPlugin import com.jarvan.fluwx.FluwxPlugin
import com.jarvan.fluwx.utils.KEY_FLUWX_REQUEST_INFO_BUNDLE
import com.jarvan.fluwx.utils.KEY_FLUWX_REQUEST_INFO_EXT_MSG
import com.jarvan.fluwx.utils.startFlutterActivity
import com.tencent.mm.opensdk.modelbase.BaseReq import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX
import java.security.cert.Extension import java.security.cert.Extension
object FluwxRequestHandler { object FluwxRequestHandler {
private const val KEY_FLUWX_REQUEST_INFO_BUNDLE = "KEY_FLUWX_REQUEST_INFO_BUNDLE"
var customOnReqDelegate: ((baseReq: BaseReq, activity: Activity) -> Unit)? = null var customOnReqDelegate: ((baseReq: BaseReq, activity: Activity) -> Unit)? = null
...@@ -43,7 +46,8 @@ object FluwxRequestHandler { ...@@ -43,7 +46,8 @@ object FluwxRequestHandler {
} }
} }
private fun handleShowMessageFromWXBundle(bundle: Bundle) = handleWXShowMessageFromWX(ShowMessageFromWX.Req(bundle)) private fun handleShowMessageFromWXBundle(bundle: Bundle) =
handleWXShowMessageFromWX(ShowMessageFromWX.Req(bundle))
private fun handleRequest(req: BaseReq) { private fun handleRequest(req: BaseReq) {
when (req) { when (req) {
...@@ -66,22 +70,21 @@ object FluwxRequestHandler { ...@@ -66,22 +70,21 @@ object FluwxRequestHandler {
// com.tencent.mm.opensdk.constants.ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX = 4 // com.tencent.mm.opensdk.constants.ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX = 4
if (!WXAPiHandler.coolBoot) { if (!WXAPiHandler.coolBoot) {
handleRequest(baseReq) handleRequest(baseReq)
startSpecifiedActivity(defaultFlutterActivityAction(activity), activity = activity) activity.startFlutterActivity()
} else { } else {
when (baseReq) { when (baseReq) {
is ShowMessageFromWX.Req -> { is ShowMessageFromWX.Req -> {
try { activity.startFlutterActivity(
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("wechatextmsg://${activity.packageName}/?extmsg=${baseReq.message.messageExt}")) wxRequestBundle = Bundle().apply {
val bundle = Bundle() baseReq.toBundle(this)
baseReq.toBundle(bundle) },
intent.putExtra(KEY_FLUWX_REQUEST_INFO_BUNDLE, bundle) bundle = Bundle().apply {
activity.startActivity(intent) putString(
activity.finish() KEY_FLUWX_REQUEST_INFO_EXT_MSG,
baseReq.message.messageExt
)
})
WXAPiHandler.coolBoot = false WXAPiHandler.coolBoot = false
}catch (e:Exception) {
Log.i("fluwx","call scheme error:${e.toString()}")
}
} }
} }
} }
...@@ -91,32 +94,18 @@ object FluwxRequestHandler { ...@@ -91,32 +94,18 @@ object FluwxRequestHandler {
fun onReq(baseReq: BaseReq, activity: Activity) { fun onReq(baseReq: BaseReq, activity: Activity) {
try { try {
val packageManager = activity.packageManager val packageManager = activity.packageManager
val appInfo = packageManager.getApplicationInfo(activity.packageName, PackageManager.GET_META_DATA) val appInfo = packageManager.getApplicationInfo(
val defaultHandle = appInfo.metaData.getBoolean("handleWeChatRequestByFluwx", true) activity.packageName,
PackageManager.GET_META_DATA
)
val defaultHandle = appInfo.metaData.getBoolean("InterruptWeChatRequestByFluwx", true)
if (defaultHandle) { if (defaultHandle) {
defaultOnReqDelegate(baseReq, activity) defaultOnReqDelegate(baseReq, activity)
} else { } else {
customOnReqDelegate?.invoke(baseReq, activity) customOnReqDelegate?.invoke(baseReq, activity)
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.i("Fluwx", "can't load meta-data handleWeChatRequestByFluwx") Log.i("Fluwx", "can't load meta-data InterruptWeChatRequestByFluwx")
}
}
private fun startSpecifiedActivity(action: String, activity: Activity, bundle: Bundle? = null, bundleKey: String? = null) {
Intent(action).run {
bundleKey?.let {
putExtra(bundleKey, bundle)
}
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
activity.packageManager?.let {
resolveActivity(it)?.also {
activity.startActivity(this)
activity.finish()
} }
} }
}
}
private fun defaultFlutterActivityAction(context: Context): String = "${context.packageName}.FlutterActivity"
} }
\ No newline at end of file
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
package com.jarvan.fluwx.handlers package com.jarvan.fluwx.handlers
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import android.util.Log import android.util.Log
import com.jarvan.fluwx.BuildConfig
import com.jarvan.fluwx.FluwxPlugin
import com.tencent.mm.opensdk.constants.Build import com.tencent.mm.opensdk.constants.Build
import com.tencent.mm.opensdk.openapi.IWXAPI import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory import com.tencent.mm.opensdk.openapi.WXAPIFactory
...@@ -54,6 +57,16 @@ object WXAPiHandler : ILog { ...@@ -54,6 +57,16 @@ object WXAPiHandler : ILog {
fun registerApp(call: MethodCall, result: MethodChannel.Result, context: Context?) { fun registerApp(call: MethodCall, result: MethodChannel.Result, context: Context?) {
context?.let {
with(it) {
val appInfo =
packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val enableLogging = appInfo.metaData.getString("WeChatDebugLogging", "")
if (enableLogging == "true" && BuildConfig.DEBUG) {
startLog()
}
}
}
if (call.argument<Boolean?>("android") == false) { if (call.argument<Boolean?>("android") == false) {
return return
} }
...@@ -89,12 +102,15 @@ object WXAPiHandler : ILog { ...@@ -89,12 +102,15 @@ object WXAPiHandler : ILog {
wxApi == null -> { wxApi == null -> {
result.error("Unassigned WxApi", "please config wxapi first", null) result.error("Unassigned WxApi", "please config wxapi first", null)
} }
wxApi?.isWXAppInstalled != true -> { wxApi?.isWXAppInstalled != true -> {
result.error("WeChat Not Installed", "Please install the WeChat first", null) result.error("WeChat Not Installed", "Please install the WeChat first", null)
} }
wxApi?.wxAppSupportAPI ?: 0 < Build.OPEN_BUSINESS_VIEW_SDK_INT -> {
(wxApi?.wxAppSupportAPI ?: 0) < Build.OPEN_BUSINESS_VIEW_SDK_INT -> {
result.error("WeChat Not Supported", "Please upgrade the WeChat version", null) result.error("WeChat Not Supported", "Please upgrade the WeChat version", null)
} }
else -> { else -> {
result.success(true) result.success(true)
} }
...@@ -102,60 +118,48 @@ object WXAPiHandler : ILog { ...@@ -102,60 +118,48 @@ object WXAPiHandler : ILog {
} }
private fun registerWxAPIInternal(appId: String, context: Context) { private fun registerWxAPIInternal(appId: String, context: Context) {
with(context) {
val appInfo =
packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val enableLogging = appInfo.metaData.getString("WeChatDebugLogging", "")
if (enableLogging == "true" && BuildConfig.DEBUG) {
startLog()
}
}
val api = WXAPIFactory.createWXAPI(context.applicationContext, appId) val api = WXAPIFactory.createWXAPI(context.applicationContext, appId)
registered = api.registerApp(appId) registered = api.registerApp(appId)
wxApi = api wxApi = api
} }
fun startLog(call: MethodCall, result: MethodChannel.Result) { fun startLog() {
wxApi?.setLogImpl(this); wxApi?.setLogImpl(this)
result.success(true);
}
fun stopLog(call: MethodCall, result: MethodChannel.Result) {
wxApi?.setLogImpl(null);
result.success(true);
} }
override fun d(p0: String?, p1: String?) { override fun d(p0: String?, p1: String?) {
when { logToFlutter(p0,p1)
p1 != null -> {
Log.d(p0, p1);
}
}
} }
override fun i(p0: String?, p1: String?) { override fun i(p0: String?, p1: String?) {
when { logToFlutter(p0,p1)
p1 != null -> {
Log.d(p0, p1);
}
}
} }
override fun e(p0: String?, p1: String?) { override fun e(p0: String?, p1: String?) {
when { logToFlutter(p0,p1)
p1 != null -> {
Log.d(p0, p1);
}
}
} }
override fun v(p0: String?, p1: String?) { override fun v(p0: String?, p1: String?) {
when { logToFlutter(p0,p1)
p1 != null -> {
Log.d(p0, p1);
}
}
} }
override fun w(p0: String?, p1: String?) { override fun w(p0: String?, p1: String?) {
when { logToFlutter(p0,p1)
p1 != null -> {
Log.d(p0, p1);
}
} }
private fun logToFlutter(tag:String?,message:String?){
FluwxPlugin.callingChannel?.invokeMethod("wechatLog", mapOf(
"detail" to "$tag : $message"
))
} }
} }
......
package com.jarvan.fluwx.utils
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
internal const val KEY_FLUWX_REQUEST_INFO_EXT_MSG = "KEY_FLUWX_REQUEST_INFO_EXT_MSG"
internal const val KEY_FLUWX_REQUEST_INFO_BUNDLE = "KEY_FLUWX_REQUEST_INFO_BUNDLE"
internal fun Activity.startFlutterActivity(
wxRequestBundle: Bundle? = null,
bundle: Bundle? = null,
) {
flutterActivityIntent()?.also { intent ->
intent.addFluwxExtras()
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
bundle?.let {
intent.putExtras(it)
}
wxRequestBundle?.let {
intent.putExtra(KEY_FLUWX_REQUEST_INFO_BUNDLE, it)
}
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Log.w("fluwx", "Can not start activity for Intent: $intent")
} finally {
finish()
}
}
}
internal fun Context.flutterActivityIntent(): Intent? {
val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val flutterActivity = appInfo.metaData.getString("FluwxFlutterActivity", "")
return if (flutterActivity.isBlank()) {
packageManager.getLaunchIntentForPackage(packageName)
} else {
Intent().also {
it.setClassName(this, "${packageName}.$flutterActivity")
}
}
}
internal fun Intent.addFluwxExtras() {
putExtra("fluwx_payload_from_fluwx", true)
}
\ No newline at end of file
...@@ -22,6 +22,8 @@ import android.os.Bundle ...@@ -22,6 +22,8 @@ import android.os.Bundle
import com.jarvan.fluwx.handlers.FluwxResponseHandler import com.jarvan.fluwx.handlers.FluwxResponseHandler
import com.jarvan.fluwx.handlers.FluwxRequestHandler import com.jarvan.fluwx.handlers.FluwxRequestHandler
import com.jarvan.fluwx.handlers.WXAPiHandler import com.jarvan.fluwx.handlers.WXAPiHandler
import com.jarvan.fluwx.utils.flutterActivityIntent
import com.jarvan.fluwx.utils.startFlutterActivity
import com.tencent.mm.opensdk.modelbase.BaseReq import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelbase.BaseResp import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
...@@ -38,19 +40,18 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler { ...@@ -38,19 +40,18 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
try { try {
if (!WXAPiHandler.wxApiRegistered) { if (!WXAPiHandler.wxApiRegistered) {
val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA) val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val wechatAppId = appInfo.metaData.getString("weChatAppId") val wechatAppId = appInfo.metaData.getString("WeChatAppId")
if (wechatAppId != null) { if (wechatAppId != null) {
WXAPiHandler.setupWxApi(wechatAppId,this) WXAPiHandler.setupWxApi(wechatAppId,this)
WXAPiHandler.coolBoot = true WXAPiHandler.coolBoot = true
} else { } else {
Log.e("fluwx","can't load meta-data weChatAppId") Log.w("fluwx","can't load meta-data weChatAppId")
} }
} }
WXAPiHandler.wxApi?.handleIntent(intent, this) WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
startSpecifiedActivity(defaultFlutterActivityAction()) this.startFlutterActivity()
finish()
} }
} }
...@@ -63,8 +64,7 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler { ...@@ -63,8 +64,7 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
WXAPiHandler.wxApi?.handleIntent(intent, this) WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
startSpecifiedActivity(defaultFlutterActivityAction()) this.startFlutterActivity()
finish()
} }
} }
...@@ -80,21 +80,4 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler { ...@@ -80,21 +80,4 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
FluwxResponseHandler.handleResponse(resp) FluwxResponseHandler.handleResponse(resp)
finish() finish()
} }
private fun startSpecifiedActivity(action: String, bundle: Bundle? = null, bundleKey: String? = null) {
Intent(action).run {
bundleKey?.let {
putExtra(bundleKey, bundle)
}
addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
packageManager?.let {
resolveActivity(packageManager)?.also {
startActivity(this)
finish()
}
}
}
}
private fun defaultFlutterActivityAction(): String = "$packageName.FlutterActivity"
} }
\ No newline at end of file
package com.jarvan.fluwx
class FluwxTest {
fun test(){}
}
\ No newline at end of file
package com.jarvan.fluwx
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlin.test.Test
import org.mockito.Mockito
/*
* This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
internal class FluwxPluginTest {
@Test
fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
val plugin = FluwxPlugin()
val call = MethodCall("getPlatformVersion", null)
val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
plugin.onMethodCall(call, mockResult)
Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
}
}
...@@ -4,8 +4,9 @@ The purpose of `sendWeChatAuth` is to get auth code and then get information for ...@@ -4,8 +4,9 @@ The purpose of `sendWeChatAuth` is to get auth code and then get information for
Getting `access_token` is not supported in `fluwx`. For `access_token`, please visit [official documents](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html). Getting `access_token` is not supported in `fluwx`. For `access_token`, please visit [official documents](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html).
```dart ```dart
sendWeChatAuth(scope: "snsapi_userinfo", state: "wechat_sdk_demo_test"); Fluwx fluwx = Fluwx();
``` fluwx.authBy(which: NormalAuth(scope: 'snsapi_userinfo', state: 'wechat_sdk_demo_test'));
```
> WHY? I think we shall fetch access_token or user info at backend. > WHY? I think we shall fetch access_token or user info at backend.
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
`sendWeChatAuth`的目的是为了获取code,拿到了code才能进行微信登录,可以通过[官方文档](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html)查看具体流程。 `sendWeChatAuth`的目的是为了获取code,拿到了code才能进行微信登录,可以通过[官方文档](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html)查看具体流程。
```dart ```dart
sendWeChatAuth(scope: "snsapi_userinfo", state: "wechat_sdk_demo_test"); Fluwx fluwx = Fluwx();
fluwx.authBy(which: NormalAuth(scope: 'snsapi_userinfo', state: 'wechat_sdk_demo_test'));
``` ```
> 为什么不支持获取用户信息? 我认为获取用户信息应该后端来做,即使没有后端,你也可以在dart层自己实现. > 为什么不支持获取用户信息? 我认为获取用户信息应该后端来做,即使没有后端,你也可以在dart层自己实现.
......
## Basic knowledge ## Basic knowledge
### Response from WeChat ### Response from WeChat
Actually, almost every result from functions like `shareToWeChat` or `payWithWeChat` which call `sendRequest` in native doesn't makes sense. The `bool` value is the result of `sendRequest`. Actually, almost every result from functions like `share` or `pay` which call `sendRequest` in native doesn't makes sense. The `bool` value is the result of `sendRequest`.
So if you want get the real result you shall do like this: So if you want get the real result you shall do like this:
```dart ```dart
fluwx.weChatResponseEventHandler.listen((res) { fluwx.subscribeResponse((response) {
if (res is fluwx.WeChatPaymentResponse) { if (response is WeChatAuthResponse) {
// do something here
} }
}); });
``` ```
Take a look at subclasses of `BaseWeChatResponse` for help. Take a look at subclasses of `WeChatResponse` for help.
> NOTE: If you get `errCode = -1`, please read the WeChatSDK document for help. There are to many cases lead to that. > NOTE: If you get `errCode = -1`, please read the WeChatSDK document for help. There are to many cases lead to that.
You can also unsubscribe response by calling `fluwx.subscribeResponse`.
### Images in WeChat ### Images in WeChat
The are four built-in types of `WeChatImage` in `fluwx`: The are four built-in types of `WeChatImage` in `fluwx`:
......
...@@ -6,15 +6,17 @@ ...@@ -6,15 +6,17 @@
为了获取真实的回调,你应该这样做: 为了获取真实的回调,你应该这样做:
```dart ```dart
fluwx.weChatResponseEventHandler.listen((res) { fluwx.subscribeResponse((response) {
if (res is fluwx.WeChatPaymentResponse) { if (response is WeChatAuthResponse) {
// do something here
} }
}); });
``` ```
> 笔记: 如果你的 `errCode = -1`, 那请阅读微信官方文档,因为-1的原因数不胜数. > 笔记: 如果你的 `errCode = -1`, 那请阅读微信官方文档,因为-1的原因数不胜数.
你也可以通过`fluwx.unsubscribeResponse`取消订阅消息。
### 图片 ### 图片
有四种内置 `WeChatImage`: 有四种内置 `WeChatImage`:
......
## Launch App from H5
Fluwx supports launch app from `<wx-open-launch-app>`, and pass `extInfo` to your app.
For Android side, you need add the following action for your FlutterActivity in `AndroidManifest.xml`:
```
<intent-filter>
<action android:name="${applicationId}.FlutterActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="${applicationId}"
android:path="/"
android:scheme="wechatextmsg" />
</intent-filter>
```
At the same time, you also need to add `<meta-data>` in application which used to store your WeChat AppId:
```xml
<meta-data
android:name="weChatAppId"
android:value="12345678" />
```
If you want to pass `extInfo` to Flutter, you need to add the following code in `MainActivity.kt`:
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//If you didn't configure WxAPI, add the following code
WXAPiHandler.setupWxApi("wxd930ea5d5a258f4f",this)
//Get Ext-Info from Intent.
FluwxRequestHandler.handleRequestInfoFromIntent(intent)
}
```
If you want to custom your request logic, you need add the `<meta-data>` in application:
```xml
<meta-data
android:name="handleWeChatRequestByFluwx"
android:value="false" />
```
And then, set `FluwxRequestHandler.customOnReqDelegate` on your own.
## on Android 11
Please add the following queries in your app's `AndroidManifest.xml`:
```xml
<queries>
<intent>
<action android:name="${applicationId}.FlutterActivity" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:host="${applicationId}"
android:path="/"
android:scheme="wechatextmsg" />
</intent>
</queries>
```
## IOS ## IOS
Please register your WXApi in your `AppDelegate`: Please register your WXApi in your `AppDelegate`:
```oc ```oc
......
## 从H5启动app
Fluwx 支持从`<wx-open-launch-app>`启动你的app, 并且支持传递`extInfo`给你的app.
对于Android来说,你要在`AndroidManifest.xml`中给你的`Activity`加上一个标签:
```
<intent-filter>
<action android:name="${applicationId}.FlutterActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="${applicationId}"
android:path="/"
android:scheme="wechatextmsg" />
</intent-filter>
```
与此同时,你还需要在需要在application中加上`<meta-data>`,把你的appId放进去:
```xml
<meta-data
android:name="weChatAppId"
android:value="12345678" />
```
如果你想把`extInfo`传给Flutter, 你要在`MainActivity`加上如下代码:
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//If you didn't configure WxAPI, add the following code
WXAPiHandler.setupWxApi("wxd930ea5d5a258f4f",this)
//Get Ext-Info from Intent.
FluwxRequestHandler.handleRequestInfoFromIntent(intent)
}
```
如果你想自定义你的调用逻辑, 你需要在application中加上`<meta-data>`:
```xml
<meta-data
android:name="handleWeChatRequestByFluwx"
android:value="false" />
```
然后, 自己实现 `FluwxRequestHandler.customOnReqDelegate`.
## 兼容Android 11
请在你的应用的`AndroidManifest.xml`中添加以下queries:
```xml
<queries>
<intent>
<action android:name="${applicationId}.FlutterActivity" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:host="${applicationId}"
android:path="/"
android:scheme="wechatextmsg" />
</intent>
</queries>
```
## IOS ## IOS
请在你的`AppDelegate`中主动注册`WXApi` 请在你的`AppDelegate`中主动注册`WXApi`
......
## Upgrade to V4
`Fluwx v4` not only brings a lot exciting functionalities but also breaking changes。
- Now we need to initialize the instance using `Fluwx fluwx = Fluwx()`
- Listening response from WeChat changed to `subscribeResponse` and also adding `unsubscribeResponse` to support
cancel listening.
- Keyword `wechat` in some functions is removed.
- Some functions are extracted to a single function,and now you can pass different params instead.
- Some configurations are moved to[pubspec.yaml](../example/pubspec.yaml),for example, you can enable/disable log in `pubspec.yaml`.
- `no_pay` can be enabled by [pubspec.yaml](../example/pubspec.yaml), reference example for more details.
\ No newline at end of file
## 升级到V4
`Fluwx v4`带来了很多令人兴奋的功能,但也带来了少破坏性更新。
- 现在我们需要使用`Fluwx fluwx = Fluwx()`初始化实例
- 监听微信回调变成了`subscribeResponse`并且增加了`unsubscribeResponse`以支持取消监听
- 很多带有`wechat`关键字的函数已经把`wechat`关键字删除了
- 很多方法被整到了一个函数中,现在你可以传递不同的对象实现对应的业务
- 一些配置被移动到了[pubspec.yaml](../example/pubspec.yaml),可以通过`pubspec.yaml`配置是否开启日志等等
- `no_pay`现在也通过[pubspec.yaml](../example/pubspec.yaml)配置,具体可以参加example.
\ No newline at end of file
...@@ -3,15 +3,16 @@ ...@@ -3,15 +3,16 @@
Calling payment is easy but to make it work isn't not so easy: Calling payment is easy but to make it work isn't not so easy:
```dart ```dart
payWithWeChat( fluwx.pay(
appId: result['appid'], which: Payment(
partnerId: result['partnerid'], appId: result['appid'].toString(),
prepayId: result['prepayid'], partnerId: result['partnerid'].toString(),
packageValue: result['package'], prepayId: result['prepayid'].toString(),
nonceStr: result['noncestr'], packageValue: result['package'].toString(),
timeStamp: result['timestamp'], nonceStr: result['noncestr'].toString(),
sign: result['sign'], timestamp: result['timestamp'],
); sign: result['sign'].toString(),
));
``` ```
Take a look at [payment document](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1#) for help. Take a look at [payment document](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=11_1#) for help.
...@@ -3,31 +3,16 @@ ...@@ -3,31 +3,16 @@
调用支付方法很简单,但想成功并不简单: 调用支付方法很简单,但想成功并不简单:
```dart ```dart
payWithWeChat( fluwx.pay(
appId: result['appid'], which: Payment(
partnerId: result['partnerid'], appId: result['appid'].toString(),
prepayId: result['prepayid'], partnerId: result['partnerid'].toString(),
packageValue: result['package'], prepayId: result['prepayid'].toString(),
nonceStr: result['noncestr'], packageValue: result['package'].toString(),
timeStamp: result['timestamp'], nonceStr: result['noncestr'].toString(),
sign: result['sign'], timestamp: result['timestamp'],
); sign: result['sign'].toString(),
``` ));
## iOS 支付
* 配置`URL Schemes` ,内容为应用的`AppID`, 可以登录微信开放平台查看。编辑`ios/Runner/Info.plist`
```xml
<key>CFBundleURLSchemes</key>
<array>
<string>wx84cxxxxxx</string>
</array>
```
* 配置`LSApplicationQueriesSchemes`
![image-20210523140138835](https://gitee.com/inkkk0516/typora/raw/master/image-20210523140138835.png)
* 使用 * 使用
......
...@@ -2,18 +2,18 @@ ...@@ -2,18 +2,18 @@
Simple and easy: Simple and easy:
```dart ```dart
shareToWeChat(WeChatShareTextModel("source text", scene: WeChatScene.SESSION)); fluwx.share(WeChatShareTextModel("source text", scene: WeChatScene.SESSION));
``` ```
The destination of sharing can be SESSION(default),TIMELINE or FAVORITE.However,mini-program only support SESSION. The destination of sharing can be SESSION(default),TIMELINE or FAVORITE.However,mini-program only support SESSION.
```dart ```dart
///[WeChatScene.SESSION]会话 ///[WeChatScene.session]会话
///[WeChatScene.TIMELINE]朋友圈 ///[WeChatScene.timeline]朋友圈
///[WeChatScene.FAVORITE]收藏 ///[WeChatScene.favorite]收藏
enum WeChatScene { enum WeChatScene {
SESSION, session,
TIMELINE, timeline,
FAVORITE favorite
} }
``` ```
......
...@@ -2,21 +2,22 @@ ...@@ -2,21 +2,22 @@
简单: 简单:
```dart ```dart
shareToWeChat(WeChatShareTextModel("source text", scene: WeChatScene.SESSION)); fluwx.share(WeChatShareTextModel("source text", scene: WeChatScene.SESSION));
``` ```
绝大部分分享可以分享到会话,朋友圈,收藏(小程序目前只能分享到会话)。默认分享到会话。 绝大部分分享可以分享到会话,朋友圈,收藏(小程序目前只能分享到会话)。默认分享到会话。
```dart ```dart
///[WeChatScene.SESSION]会话 ///[WeChatScene.session]会话
///[WeChatScene.TIMELINE]朋友圈 ///[WeChatScene.timeline]朋友圈
///[WeChatScene.FAVORITE]收藏 ///[WeChatScene.favorite]收藏
enum WeChatScene { enum WeChatScene {
SESSION, session,
TIMELINE, timeline,
FAVORITE favorite
} }
``` ```
支持的分享各类: 支持的分享各类:
- WeChatShareTextModel - WeChatShareTextModel
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
**/Podfile.lock migrate_working_dir/
# IntelliJ related # IntelliJ related
*.iml *.iml
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
**/ios/Flutter/.last_build_id **/ios/Flutter/.last_build_id
**/ios/Flutter/flutter_export_environment.sh
.dart_tool/ .dart_tool/
.flutter-plugins .flutter-plugins
.flutter-plugins-dependencies .flutter-plugins-dependencies
...@@ -33,11 +32,13 @@ ...@@ -33,11 +32,13 @@
.pub/ .pub/
/build/ /build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related # Symbolication related
app.*.symbols app.*.symbols
# Obfuscation related # Obfuscation related
app.*.map.json app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
channel: stable
project_type: app
...@@ -8,9 +8,9 @@ This project is a starting point for a Flutter application. ...@@ -8,9 +8,9 @@ This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project: A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter, view our For help getting started with Flutter development, view the
[online documentation](https://flutter.dev/docs), which offers tutorials, [online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference. samples, guidance on mobile development, and a full API reference.
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
gradle-wrapper.jar gradle-wrapper.jar
**.classpath
**.project
**.settings
/.gradle /.gradle
/captures/ /captures/
/gradlew /gradlew
/gradlew.bat /gradlew.bat
/local.properties /local.properties
GeneratedPluginRegistrant.java GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
...@@ -8,7 +8,6 @@ if (localPropertiesFile.exists()) { ...@@ -8,7 +8,6 @@ if (localPropertiesFile.exists()) {
def flutterRoot = localProperties.getProperty('flutter.sdk') def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) { if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
} }
...@@ -27,27 +26,26 @@ apply plugin: 'kotlin-android' ...@@ -27,27 +26,26 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 31 namespace "com.jarvan.fluwx_example"
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
} }
lintOptions {
disable 'InvalidPackage'
}
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "net.sourceforge.simcpux" applicationId "net.sourceforge.simcpux"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 31 targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
flavorDimensions "branch"
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
...@@ -73,7 +71,4 @@ flutter { ...@@ -73,7 +71,4 @@ flutter {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
} }
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.jarvan.fluwx_example">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that <!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method. calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide In most cases you can leave this as-is, but you if you want to provide
...@@ -28,27 +27,15 @@ ...@@ -28,27 +27,15 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:exported="true"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="${applicationId}.FlutterActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:host="${applicationId}"
android:path="/"
android:scheme="wechatextmsg" />
</intent-filter>
</activity> </activity>
<!-- Don't delete the meta-data below. <!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
......
...@@ -5,7 +5,6 @@ import android.os.Bundle ...@@ -5,7 +5,6 @@ import android.os.Bundle
import com.jarvan.fluwx.handlers.FluwxRequestHandler import com.jarvan.fluwx.handlers.FluwxRequestHandler
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() { class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when <!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame --> the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item> <item name="android:windowBackground">@drawable/launch_background</item>
</style> </style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources> </resources>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
...@@ -6,7 +6,7 @@ buildscript { ...@@ -6,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
...@@ -26,6 +26,6 @@ subprojects { ...@@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
task clean(type: Delete) { tasks.register("clean", Delete) {
delete rootProject.buildDir delete rootProject.buildDir
} }
...@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME ...@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
include ':app' pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}
settings.ext.flutterSdkPath = flutterSdkPath()
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
def plugins = new Properties() plugins {
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
if (pluginsFile.exists()) { }
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
} }
plugins.each { name, path -> include ":app"
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name" apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
project(":$name").projectDir = pluginDirectory
}
// This is a basic Flutter integration test.
//
// Since integration tests run in a full Flutter application, they can interact
// with the host side of a plugin implementation, unlike Dart unit tests.
//
// For more information about Flutter integration tests, please see
// https://docs.flutter.dev/cookbook/testing/integration/introduction
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:fluwx/fluwx.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
});
}
**/dgph
*.mode1v3 *.mode1v3
*.mode2v3 *.mode2v3
*.moved-aside *.moved-aside
...@@ -11,7 +12,6 @@ ...@@ -11,7 +12,6 @@
Icon? Icon?
**/Pods/ **/Pods/
**/.symlinks/ **/.symlinks/
Podfile.lock
profile profile
xcuserdata xcuserdata
**/.generated/ **/.generated/
...@@ -19,6 +19,7 @@ Flutter/App.framework ...@@ -19,6 +19,7 @@ Flutter/App.framework
Flutter/Flutter.framework Flutter/Flutter.framework
Flutter/Flutter.podspec Flutter/Flutter.podspec
Flutter/Generated.xcconfig Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx Flutter/app.flx
Flutter/app.zip Flutter/app.zip
Flutter/flutter_assets/ Flutter/flutter_assets/
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>en</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>App</string> <string>App</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
......
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"
...@@ -29,6 +29,9 @@ flutter_ios_podfile_setup ...@@ -29,6 +29,9 @@ flutter_ios_podfile_setup
target 'Runner' do target 'Runner' do
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end end
post_install do |installer| post_install do |installer|
......
PODS:
- Flutter (1.0.0)
- fluwx (0.0.1):
- Flutter
- fluwx/no_pay (= 0.0.1)
- fluwx/no_pay (0.0.1):
- Flutter
- "OpenWeChatSDKNoPay (~> 2.0.2+1)"
- integration_test (0.0.1):
- Flutter
- OpenWeChatSDKNoPay (2.0.2)
DEPENDENCIES:
- Flutter (from `Flutter`)
- fluwx (from `.symlinks/plugins/fluwx/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
SPEC REPOS:
trunk:
- OpenWeChatSDKNoPay
EXTERNAL SOURCES:
Flutter:
:path: Flutter
fluwx:
:path: ".symlinks/plugins/fluwx/ios"
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluwx: f608fff0e3a8c30199b626fed590d83cdd820a52
integration_test: 13825b8a9334a850581300559b8839134b124670
OpenWeChatSDKNoPay: 59a9628a746352bb400329cb7f12e6dc7096bf6e
PODFILE CHECKSUM: beab77b38961de946f08660e554f80ac174dc842
COCOAPODS: 1.12.1
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
...@@ -37,6 +37,17 @@ ...@@ -37,6 +37,17 @@
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<Testables> <Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "331C80F0294D02FB00263BE5"
BuildableName = "RunnerTests.xctest"
BlueprintName = "RunnerTests"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables> </Testables>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
...@@ -2,10 +2,16 @@ ...@@ -2,10 +2,16 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Fluwx</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleGetInfoString</key>
<string/>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
...@@ -20,22 +26,39 @@ ...@@ -20,22 +26,39 @@
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict/>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Editor</string> <string>Editor</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>wxd930ea5d5a258f4f</string> <string>weixin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>123456</string>
</array>
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string> <string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSApplicationCategoryType</key>
<string/>
<key>LSApplicationQueriesSchemes</key> <key>LSApplicationQueriesSchemes</key>
<array> <array>
<string>weixin</string> <string>weixin</string>
<string>weixinULAPI</string> <string>weixinULAPI</string>
<string>weixinURLParamsAPI</string>
</array> </array>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>LaunchScreen</string> <string>LaunchScreen</string>
<key>UIMainStoryboardFile</key> <key>UIMainStoryboardFile</key>
...@@ -55,9 +78,5 @@ ...@@ -55,9 +78,5 @@
</array> </array>
<key>UIViewControllerBasedStatusBarAppearance</key> <key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict> </dict>
</plist> </plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:testdomain.com</string>
</array>
</dict>
</plist>
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
@import fluwx;
// This demonstrates a simple unit test of the Objective-C portion of this plugin's implementation.
//
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
@interface RunnerTests : XCTestCase
@end
@implementation RunnerTests
- (void)testExample {
FluwxPlugin *plugin = [[FluwxPlugin alloc] init];
FlutterMethodCall *call = [FlutterMethodCall methodCallWithMethodName:@"getPlatformVersion"
arguments:nil];
XCTestExpectation *expectation = [self expectationWithDescription:@"result block must be called"];
[plugin handleMethodCall:call
result:^(id result) {
NSString *expected = [NSString
stringWithFormat:@"iOS %@", UIDevice.currentDevice.systemVersion];
XCTAssertEqualObjects(result, expected);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:nil];
}
@end
...@@ -26,6 +26,8 @@ class MyApp extends StatefulWidget { ...@@ -26,6 +26,8 @@ class MyApp extends StatefulWidget {
} }
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
Fluwx fluwx = Fluwx();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
...@@ -33,14 +35,14 @@ class _MyAppState extends State<MyApp> { ...@@ -33,14 +35,14 @@ class _MyAppState extends State<MyApp> {
} }
_initFluwx() async { _initFluwx() async {
await registerWxApi( await fluwx.registerApi(
appId: 'wxd930ea5d5a258f4f', appId: 'wxd930ea5d5a258f4f',
doOnAndroid: true, doOnAndroid: true,
doOnIOS: true, doOnIOS: true,
universalLink: 'https://your.univerallink.com/link/', universalLink: 'https://your.univerallink.com/link/',
); );
var result = await isWeChatInstalled; var result = await fluwx.isWeChatInstalled;
print('is installed $result'); debugPrint('is installed $result');
} }
// Platform messages are asynchronous, so we initialize in an async method. // Platform messages are asynchronous, so we initialize in an async method.
...@@ -51,20 +53,20 @@ class _MyAppState extends State<MyApp> { ...@@ -51,20 +53,20 @@ class _MyAppState extends State<MyApp> {
return MaterialApp( return MaterialApp(
routes: <String, WidgetBuilder>{ routes: <String, WidgetBuilder>{
'shareText': (context) => ShareTextPage(), 'shareText': (context) => ShareTextPage(),
'shareImage': (context) => ShareImagePage(), 'shareImage': (context) => const ShareImagePage(),
'shareWebPage': (context) => ShareWebPagePage(), 'shareWebPage': (context) => const ShareWebPagePage(),
'shareMusic': (context) => ShareMusicPage(), 'shareMusic': (context) => const ShareMusicPage(),
'shareVideo': (context) => ShareVideoPage(), 'shareVideo': (context) => const ShareVideoPage(),
'sendAuth': (context) => SendAuthPage(), 'sendAuth': (context) => const SendAuthPage(),
'shareMiniProgram': (context) => ShareMiniProgramPage(), 'shareMiniProgram': (context) => ShareMiniProgramPage(),
'pay': (context) => PayPage(), 'pay': (context) => const PayPage(),
'launchMiniProgram': (context) => LaunchMiniProgramPage(), 'launchMiniProgram': (context) => const LaunchMiniProgramPage(),
'subscribeMessage': (ctx) => SubscribeMessagePage(), 'subscribeMessage': (ctx) => const SubscribeMessagePage(),
'AuthByQRCode': (ctx) => AuthByQRCodePage(), 'AuthByQRCode': (ctx) => const AuthByQRCodePage(),
'AutoDeduct': (ctx) => SignAutoDeductPage(), 'AutoDeduct': (ctx) => const SignAutoDeductPage(),
}, },
home: Scaffold( home: Scaffold(
appBar: AppBar(title: const Text('Plugin example app')), appBar: AppBar(title: const Text('Fluwx sample')),
body: ShareSelectorPage(), body: ShareSelectorPage(),
), ),
); );
...@@ -72,6 +74,10 @@ class _MyAppState extends State<MyApp> { ...@@ -72,6 +74,10 @@ class _MyAppState extends State<MyApp> {
} }
class ShareSelectorPage extends StatelessWidget { class ShareSelectorPage extends StatelessWidget {
final Fluwx fluwx = Fluwx();
ShareSelectorPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return Center(
...@@ -81,32 +87,12 @@ class ShareSelectorPage extends StatelessWidget { ...@@ -81,32 +87,12 @@ class ShareSelectorPage extends StatelessWidget {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: OutlinedButton( child: OutlinedButton(
onPressed: () async { onPressed: () async {
String? extMsg = await getExtMsg(); String? extMsg = await fluwx.getExtMsg();
print('extMsg:$extMsg\n'); debugPrint('extMsg:$extMsg\n');
}, },
child: const Text('Get ExtMessage'), child: const Text('Get ExtMessage'),
), ),
), ),
Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () async {
bool? success = await startLog(logLevel: WXLogLevel.NORMAL);
print('startLog:$success\n');
},
child: const Text('start log'),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: OutlinedButton(
onPressed: () async {
dynamic success = await stopLog();
print('stopLog:$success\n');
},
child: const Text('stop log'),
),
),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: OutlinedButton( child: OutlinedButton(
...@@ -219,7 +205,7 @@ class ShareSelectorPage extends StatelessWidget { ...@@ -219,7 +205,7 @@ class ShareSelectorPage extends StatelessWidget {
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: OutlinedButton( child: OutlinedButton(
onPressed: () { onPressed: () {
openWeChatApp(); fluwx.open(target: WeChatApp());
}, },
child: const Text('Open WeChat App'), child: const Text('Open WeChat App'),
), ),
......
...@@ -6,11 +6,11 @@ class AuthByQRCodePage extends StatefulWidget { ...@@ -6,11 +6,11 @@ class AuthByQRCodePage extends StatefulWidget {
const AuthByQRCodePage({Key? key}) : super(key: key); const AuthByQRCodePage({Key? key}) : super(key: key);
@override @override
_AuthByQRCodePageState createState() => _AuthByQRCodePageState(); State<AuthByQRCodePage> createState() => _AuthByQRCodePageState();
} }
class _AuthByQRCodePageState extends State<AuthByQRCodePage> { class _AuthByQRCodePageState extends State<AuthByQRCodePage> {
String _status = 'status'; final String _status = 'status';
Uint8List? _image; Uint8List? _image;
@override @override
......
...@@ -5,30 +5,35 @@ class LaunchMiniProgramPage extends StatefulWidget { ...@@ -5,30 +5,35 @@ class LaunchMiniProgramPage extends StatefulWidget {
const LaunchMiniProgramPage({Key? key}) : super(key: key); const LaunchMiniProgramPage({Key? key}) : super(key: key);
@override @override
_LaunchMiniProgramPageState createState() => _LaunchMiniProgramPageState(); State<LaunchMiniProgramPage> createState() => _LaunchMiniProgramPageState();
} }
class _LaunchMiniProgramPageState extends State<LaunchMiniProgramPage> { class _LaunchMiniProgramPageState extends State<LaunchMiniProgramPage> {
String? _result = '无'; String? _result = '无';
final Fluwx fluwx = Fluwx();
late Function(WeChatResponse) responseListener;
@override
void dispose() {
super.dispose();
_result = null;
fluwx.unsubscribeResponse(responseListener);
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
weChatResponseEventHandler.listen((res) { responseListener = (response) {
if (res is WeChatLaunchMiniProgramResponse) { if (response is WeChatLaunchMiniProgramResponse) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_result = 'isSuccessful:${res.isSuccessful}'; _result = 'isSuccessful:${response.isSuccessful}';
}); });
} }
} }
}); };
}
@override fluwx.subscribeResponse(responseListener);
void dispose() {
super.dispose();
_result = null;
} }
@override @override
...@@ -41,7 +46,7 @@ class _LaunchMiniProgramPageState extends State<LaunchMiniProgramPage> { ...@@ -41,7 +46,7 @@ class _LaunchMiniProgramPageState extends State<LaunchMiniProgramPage> {
children: <Widget>[ children: <Widget>[
OutlinedButton( OutlinedButton(
onPressed: () { onPressed: () {
launchWeChatMiniProgram(username: 'gh_d43f693ca31f'); fluwx.open(target: MiniProgram(username: 'gh_d43f693ca31f'));
}, },
child: const Text('Launch MiniProgrom'), child: const Text('Launch MiniProgrom'),
), ),
......
...@@ -2,34 +2,38 @@ import 'dart:convert'; ...@@ -2,34 +2,38 @@ import 'dart:convert';
import 'dart:io' as H; import 'dart:io' as H;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluwx/fluwx.dart' as fluwx; import 'package:fluwx/fluwx.dart';
class PayPage extends StatefulWidget { class PayPage extends StatefulWidget {
const PayPage({Key? key}) : super(key: key); const PayPage({Key? key}) : super(key: key);
@override @override
_PayPageState createState() => _PayPageState(); State<PayPage> createState() => _PayPageState();
} }
class _PayPageState extends State<PayPage> { class _PayPageState extends State<PayPage> {
String _url = 'https://wxpay.wxutil.com/pub_v2/app/app_pay.php'; final Fluwx fluwx = Fluwx();
final String _url = 'https://wxpay.wxutil.com/pub_v2/app/app_pay.php';
String _result = '无'; String _result = '无';
late Function(WeChatResponse) responseListener;
@override
void dispose() {
super.dispose();
fluwx.unsubscribeResponse(responseListener);
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
fluwx.weChatResponseEventHandler.listen((res) { responseListener = (response) {
if (res is fluwx.WeChatPaymentResponse) { if (response is WeChatPaymentResponse) {
setState(() { setState(() {
_result = 'pay :${res.isSuccessful}'; _result = 'pay :${response.isSuccessful}';
}); });
} }
}); };
// fluwx.responseFromPayment.listen((data) { fluwx.subscribeResponse(responseListener);
// setState(() {
// _result = '${data.errCode}';
// });
// });
} }
@override @override
...@@ -46,23 +50,21 @@ class _PayPageState extends State<PayPage> { ...@@ -46,23 +50,21 @@ class _PayPageState extends State<PayPage> {
}; };
var request = await h.getUrl(Uri.parse(_url)); var request = await h.getUrl(Uri.parse(_url));
var response = await request.close(); var response = await request.close();
var data = await Utf8Decoder().bind(response).join(); var data = await const Utf8Decoder().bind(response).join();
Map<String, dynamic> result = json.decode(data); Map<String, dynamic> result = json.decode(data);
print(result['appid']); debugPrint(result['appid']);
print(result['timestamp']); debugPrint(result['timestamp']);
fluwx fluwx
.payWithWeChat( .pay(
which: Payment(
appId: result['appid'].toString(), appId: result['appid'].toString(),
partnerId: result['partnerid'].toString(), partnerId: result['partnerid'].toString(),
prepayId: result['prepayid'].toString(), prepayId: result['prepayid'].toString(),
packageValue: result['package'].toString(), packageValue: result['package'].toString(),
nonceStr: result['noncestr'].toString(), nonceStr: result['noncestr'].toString(),
timeStamp: result['timestamp'], timestamp: result['timestamp'],
sign: result['sign'].toString(), sign: result['sign'].toString(),
) ));
.then((data) {
print('---》$data');
});
}, },
child: const Text('pay'), child: const Text('pay'),
), ),
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluwx/fluwx.dart' as fluwx; import 'package:fluwx/fluwx.dart';
class SendAuthPage extends StatefulWidget { class SendAuthPage extends StatefulWidget {
const SendAuthPage({Key? key}) : super(key: key); const SendAuthPage({Key? key}) : super(key: key);
@override @override
_SendAuthPageState createState() => _SendAuthPageState(); State<SendAuthPage> createState() => _SendAuthPageState();
} }
class _SendAuthPageState extends State<SendAuthPage> { class _SendAuthPageState extends State<SendAuthPage> {
String? _result = '无'; String? _result = '无';
Fluwx fluwx = Fluwx();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
fluwx.weChatResponseEventHandler.distinct((a, b) => a == b).listen((res) { fluwx.subscribeResponse((response) {
if (res is fluwx.WeChatAuthResponse) { if (response is WeChatAuthResponse) {
setState(() { setState(() {
_result = 'state :${res.state} \n code:${res.code}'; _result = 'state :${response.state} \n code:${response.code}';
}); });
} }
}); });
...@@ -38,10 +39,11 @@ class _SendAuthPageState extends State<SendAuthPage> { ...@@ -38,10 +39,11 @@ class _SendAuthPageState extends State<SendAuthPage> {
OutlinedButton( OutlinedButton(
onPressed: () { onPressed: () {
fluwx fluwx
.sendWeChatAuth( .authBy(
which: NormalAuth(
scope: 'snsapi_userinfo', scope: 'snsapi_userinfo',
state: 'wechat_sdk_demo_test', state: 'wechat_sdk_demo_test',
) ))
.then((data) {}); .then((data) {});
}, },
child: const Text('send auth'), child: const Text('send auth'),
......
...@@ -5,20 +5,21 @@ class ShareImagePage extends StatefulWidget { ...@@ -5,20 +5,21 @@ class ShareImagePage extends StatefulWidget {
const ShareImagePage({Key? key}) : super(key: key); const ShareImagePage({Key? key}) : super(key: key);
@override @override
_ShareImagePageState createState() => _ShareImagePageState(); State<ShareImagePage> createState() => _ShareImagePageState();
} }
class _ShareImagePageState extends State<ShareImagePage> { class _ShareImagePageState extends State<ShareImagePage> {
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
String _response = ''; String _response = '';
WeChatImage? source; WeChatImage? source;
WeChatImage? thumbnail; WeChatImage? thumbnail;
Fluwx fluwx = Fluwx();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
weChatResponseEventHandler.listen((res) { fluwx.subscribeResponse((res) {
if (res is WeChatShareResponse) { if (res is WeChatShareResponse) {
setState(() { setState(() {
_response = 'state :${res.isSuccessful}'; _response = 'state :${res.isSuccessful}';
...@@ -34,7 +35,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -34,7 +35,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
title: const Text('shareImage'), title: const Text('shareImage'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.share, color: Colors.white), icon: const Icon(Icons.share, color: Colors.white),
onPressed: _shareImage, onPressed: _shareImage,
), ),
], ],
...@@ -44,7 +45,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -44,7 +45,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
TextField( TextField(
decoration: InputDecoration(labelText: '图片地址(仅限网络)'), decoration: const InputDecoration(labelText: '图片地址(仅限网络)'),
controller: TextEditingController( controller: TextEditingController(
text: 'https://timgsa.baidu.com/timg' text: 'https://timgsa.baidu.com/timg'
'?image' '?image'
...@@ -73,7 +74,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -73,7 +74,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.SESSION, value: WeChatScene.session,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -85,7 +86,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -85,7 +86,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.TIMELINE, value: WeChatScene.timeline,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -97,7 +98,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -97,7 +98,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.FAVORITE, value: WeChatScene.favorite,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -116,7 +117,7 @@ class _ShareImagePageState extends State<ShareImagePage> { ...@@ -116,7 +117,7 @@ class _ShareImagePageState extends State<ShareImagePage> {
} }
void _shareImage() { void _shareImage() {
shareToWeChat(WeChatShareImageModel(source!, thumbnail: thumbnail)); fluwx.share(WeChatShareImageModel(source!, thumbnail: thumbnail));
} }
void handleRadioValueChanged(WeChatScene scene) { void handleRadioValueChanged(WeChatScene scene) {
......
...@@ -2,12 +2,14 @@ import 'package:flutter/material.dart'; ...@@ -2,12 +2,14 @@ import 'package:flutter/material.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
class ShareMiniProgramPage extends StatefulWidget { class ShareMiniProgramPage extends StatefulWidget {
const ShareMiniProgramPage({Key? key}) : super(key: key);
@override @override
_ShareMiniProgramPageState createState() => _ShareMiniProgramPageState(); State<ShareMiniProgramPage> createState() => _ShareMiniProgramPageState();
} }
class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> { class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> {
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
String _webPageUrl = 'http://www.qq.com'; String _webPageUrl = 'http://www.qq.com';
String _thumbnail = 'https://timgsa.baidu.com/timg' String _thumbnail = 'https://timgsa.baidu.com/timg'
'?image' '?image'
...@@ -22,6 +24,8 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> { ...@@ -22,6 +24,8 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> {
String _path = '/pages/media'; String _path = '/pages/media';
String _description = 'Fluwx'; String _description = 'Fluwx';
Fluwx fluwx = Fluwx();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
...@@ -29,7 +33,7 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> { ...@@ -29,7 +33,7 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> {
title: const Text('ShareMiniProgram'), title: const Text('ShareMiniProgram'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.share, color: Colors.white), icon: const Icon(Icons.share, color: Colors.white),
onPressed: _share, onPressed: _share,
), ),
], ],
...@@ -95,6 +99,6 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> { ...@@ -95,6 +99,6 @@ class _ShareMiniProgramPageState extends State<ShareMiniProgramPage> {
description: _description, description: _description,
thumbnail: WeChatImage.network(_thumbnail), thumbnail: WeChatImage.network(_thumbnail),
); );
shareToWeChat(model); fluwx.share(model);
} }
} }
...@@ -5,7 +5,7 @@ class ShareMusicPage extends StatefulWidget { ...@@ -5,7 +5,7 @@ class ShareMusicPage extends StatefulWidget {
const ShareMusicPage({Key? key}) : super(key: key); const ShareMusicPage({Key? key}) : super(key: key);
@override @override
_ShareMusicPageState createState() => _ShareMusicPageState(); State<ShareMusicPage> createState() => _ShareMusicPageState();
} }
class _ShareMusicPageState extends State<ShareMusicPage> { class _ShareMusicPageState extends State<ShareMusicPage> {
...@@ -15,7 +15,8 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -15,7 +15,8 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
String _title = 'Beyond'; String _title = 'Beyond';
String _description = 'A Popular Rock Band From China'; String _description = 'A Popular Rock Band From China';
String _thumnail = 'images/logo.png'; String _thumnail = 'images/logo.png';
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
Fluwx _fluwx = Fluwx();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -24,7 +25,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -24,7 +25,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
title: const Text('ShareMusicPage'), title: const Text('ShareMusicPage'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.share, color: Colors.white), icon: const Icon(Icons.share, color: Colors.white),
onPressed: _share, onPressed: _share,
), ),
], ],
...@@ -41,21 +42,22 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -41,21 +42,22 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
onChanged: (str) { onChanged: (str) {
_musicUrl = str; _musicUrl = str;
}, },
decoration: InputDecoration(labelText: 'music url'), decoration: const InputDecoration(labelText: 'music url'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'http://www.qq.com'), controller: TextEditingController(text: 'http://www.qq.com'),
onChanged: (str) { onChanged: (str) {
_musicLowBandUrl = str; _musicLowBandUrl = str;
}, },
decoration: InputDecoration(labelText: 'music low band url'), decoration:
const InputDecoration(labelText: 'music low band url'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'Beyond'), controller: TextEditingController(text: 'Beyond'),
onChanged: (str) { onChanged: (str) {
_title = str; _title = str;
}, },
decoration: InputDecoration(labelText: 'title'), decoration: const InputDecoration(labelText: 'title'),
), ),
TextField( TextField(
controller: TextEditingController( controller: TextEditingController(
...@@ -64,14 +66,14 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -64,14 +66,14 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
onChanged: (str) { onChanged: (str) {
_description = str; _description = str;
}, },
decoration: InputDecoration(labelText: 'description'), decoration: const InputDecoration(labelText: 'description'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'images/logo.png'), controller: TextEditingController(text: 'images/logo.png'),
onChanged: (str) { onChanged: (str) {
_thumnail = str; _thumnail = str;
}, },
decoration: InputDecoration(labelText: 'thumbnail'), decoration: const InputDecoration(labelText: 'thumbnail'),
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
...@@ -79,7 +81,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -79,7 +81,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.SESSION, value: WeChatScene.session,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -91,7 +93,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -91,7 +93,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.TIMELINE, value: WeChatScene.timeline,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -103,7 +105,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -103,7 +105,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.FAVORITE, value: WeChatScene.favorite,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -130,7 +132,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> { ...@@ -130,7 +132,7 @@ class _ShareMusicPageState extends State<ShareMusicPage> {
thumbnail: WeChatImage.network(_thumnail), thumbnail: WeChatImage.network(_thumnail),
); );
shareToWeChat(model); _fluwx.share(model);
} }
void handleRadioValueChanged(WeChatScene scene) { void handleRadioValueChanged(WeChatScene scene) {
......
...@@ -2,13 +2,16 @@ import 'package:flutter/material.dart'; ...@@ -2,13 +2,16 @@ import 'package:flutter/material.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
class ShareTextPage extends StatefulWidget { class ShareTextPage extends StatefulWidget {
const ShareTextPage({Key? key}) : super(key: key);
@override @override
_ShareTextPageState createState() => _ShareTextPageState(); State<ShareTextPage> createState() => _ShareTextPageState();
} }
class _ShareTextPageState extends State<ShareTextPage> { class _ShareTextPageState extends State<ShareTextPage> {
String _text = 'share text from fluwx'; String _text = 'share text from fluwx';
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
Fluwx fluwx = Fluwx();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -31,7 +34,7 @@ class _ShareTextPageState extends State<ShareTextPage> { ...@@ -31,7 +34,7 @@ class _ShareTextPageState extends State<ShareTextPage> {
onChanged: (str) { onChanged: (str) {
_text = str; _text = str;
}, },
decoration: InputDecoration(labelText: 'TextToShare'), decoration: const InputDecoration(labelText: 'TextToShare'),
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
...@@ -39,7 +42,7 @@ class _ShareTextPageState extends State<ShareTextPage> { ...@@ -39,7 +42,7 @@ class _ShareTextPageState extends State<ShareTextPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.SESSION, value: WeChatScene.session,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -51,7 +54,7 @@ class _ShareTextPageState extends State<ShareTextPage> { ...@@ -51,7 +54,7 @@ class _ShareTextPageState extends State<ShareTextPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.TIMELINE, value: WeChatScene.timeline,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -63,7 +66,7 @@ class _ShareTextPageState extends State<ShareTextPage> { ...@@ -63,7 +66,7 @@ class _ShareTextPageState extends State<ShareTextPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.FAVORITE, value: WeChatScene.favorite,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -81,9 +84,7 @@ class _ShareTextPageState extends State<ShareTextPage> { ...@@ -81,9 +84,7 @@ class _ShareTextPageState extends State<ShareTextPage> {
} }
void _shareText() { void _shareText() {
shareToWeChat(WeChatShareTextModel(_text, scene: scene)).then((data) { fluwx.share(WeChatShareTextModel(_text, scene: scene));
print('-->$data');
});
} }
void handleRadioValueChanged(WeChatScene scene) { void handleRadioValueChanged(WeChatScene scene) {
......
...@@ -5,16 +5,18 @@ class ShareVideoPage extends StatefulWidget { ...@@ -5,16 +5,18 @@ class ShareVideoPage extends StatefulWidget {
const ShareVideoPage({Key? key}) : super(key: key); const ShareVideoPage({Key? key}) : super(key: key);
@override @override
_ShareMusicPageState createState() => _ShareMusicPageState(); State<ShareVideoPage> createState() => _ShareVideoPageState();
} }
class _ShareMusicPageState extends State<ShareVideoPage> { class _ShareVideoPageState extends State<ShareVideoPage> {
String _videoUrl = 'http://www.qq.com'; String _videoUrl = 'http://www.qq.com';
String _videoLowBandUrl = 'http://www.qq.com'; String _videoLowBandUrl = 'http://www.qq.com';
String _title = 'Beyond'; String _title = 'Beyond';
String _description = 'A Popular Rock Band From China'; String _description = 'A Popular Rock Band From China';
String _thumnail = 'images/logo.png'; String _thumnail = 'images/logo.png';
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
Fluwx fluwx = Fluwx();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -23,7 +25,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -23,7 +25,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
title: const Text('ShareVideoPage'), title: const Text('ShareVideoPage'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.share, color: Colors.white), icon: const Icon(Icons.share, color: Colors.white),
onPressed: _share, onPressed: _share,
), ),
], ],
...@@ -40,21 +42,22 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -40,21 +42,22 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
onChanged: (str) { onChanged: (str) {
_videoUrl = str; _videoUrl = str;
}, },
decoration: InputDecoration(labelText: 'video url'), decoration: const InputDecoration(labelText: 'video url'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'http://www.qq.com'), controller: TextEditingController(text: 'http://www.qq.com'),
onChanged: (str) { onChanged: (str) {
_videoLowBandUrl = str; _videoLowBandUrl = str;
}, },
decoration: InputDecoration(labelText: 'video low band url'), decoration:
const InputDecoration(labelText: 'video low band url'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'Beyond'), controller: TextEditingController(text: 'Beyond'),
onChanged: (str) { onChanged: (str) {
_title = str; _title = str;
}, },
decoration: InputDecoration(labelText: 'title'), decoration: const InputDecoration(labelText: 'title'),
), ),
TextField( TextField(
controller: controller:
...@@ -62,14 +65,14 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -62,14 +65,14 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
onChanged: (str) { onChanged: (str) {
_description = str; _description = str;
}, },
decoration: InputDecoration(labelText: 'description'), decoration: const InputDecoration(labelText: 'description'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'images/logo.png'), controller: TextEditingController(text: 'images/logo.png'),
onChanged: (str) { onChanged: (str) {
_thumnail = str; _thumnail = str;
}, },
decoration: InputDecoration(labelText: 'thumbnail'), decoration: const InputDecoration(labelText: 'thumbnail'),
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
...@@ -77,7 +80,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -77,7 +80,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.SESSION, value: WeChatScene.session,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -89,7 +92,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -89,7 +92,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.TIMELINE, value: WeChatScene.timeline,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -101,7 +104,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -101,7 +104,7 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.FAVORITE, value: WeChatScene.favorite,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -124,10 +127,10 @@ class _ShareMusicPageState extends State<ShareVideoPage> { ...@@ -124,10 +127,10 @@ class _ShareMusicPageState extends State<ShareVideoPage> {
videoLowBandUrl: _videoLowBandUrl, videoLowBandUrl: _videoLowBandUrl,
thumbnail: WeChatImage.network(_thumnail), thumbnail: WeChatImage.network(_thumnail),
description: _description, description: _description,
scene: this.scene, scene: scene,
title: _title, title: _title,
); );
shareToWeChat(model); fluwx.share(model);
} }
void handleRadioValueChanged(WeChatScene scene) { void handleRadioValueChanged(WeChatScene scene) {
......
...@@ -12,7 +12,9 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -12,7 +12,9 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
String _url = 'share text from fluwx'; String _url = 'share text from fluwx';
String _title = 'Fluwx'; String _title = 'Fluwx';
String _thumnail = 'images/logo.png'; String _thumnail = 'images/logo.png';
WeChatScene scene = WeChatScene.SESSION; WeChatScene scene = WeChatScene.session;
Fluwx fluwx = Fluwx();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -21,7 +23,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -21,7 +23,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
title: const Text('ShareWebPage'), title: const Text('ShareWebPage'),
actions: <Widget>[ actions: <Widget>[
IconButton( IconButton(
icon: Icon(Icons.share, color: Colors.white), icon: const Icon(Icons.share, color: Colors.white),
onPressed: _share, onPressed: _share,
), ),
], ],
...@@ -37,21 +39,21 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -37,21 +39,21 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
onChanged: (str) { onChanged: (str) {
_url = str; _url = str;
}, },
decoration: InputDecoration(labelText: 'web page'), decoration: const InputDecoration(labelText: 'web page'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'Fluwx'), controller: TextEditingController(text: 'Fluwx'),
onChanged: (str) { onChanged: (str) {
_title = str; _title = str;
}, },
decoration: InputDecoration(labelText: 'thumbnail'), decoration: const InputDecoration(labelText: 'thumbnail'),
), ),
TextField( TextField(
controller: TextEditingController(text: 'images/logo.png'), controller: TextEditingController(text: 'images/logo.png'),
onChanged: (str) { onChanged: (str) {
_thumnail = str; _thumnail = str;
}, },
decoration: InputDecoration(labelText: 'thumbnail'), decoration: const InputDecoration(labelText: 'thumbnail'),
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
...@@ -59,7 +61,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -59,7 +61,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.SESSION, value: WeChatScene.session,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -71,7 +73,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -71,7 +73,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.TIMELINE, value: WeChatScene.timeline,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -83,7 +85,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -83,7 +85,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
Row( Row(
children: <Widget>[ children: <Widget>[
Radio<WeChatScene>( Radio<WeChatScene>(
value: WeChatScene.FAVORITE, value: WeChatScene.favorite,
groupValue: scene, groupValue: scene,
onChanged: (v) { onChanged: (v) {
if (v != null) handleRadioValueChanged(v); if (v != null) handleRadioValueChanged(v);
...@@ -107,7 +109,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> { ...@@ -107,7 +109,7 @@ class ShareWebPagePageState extends State<ShareWebPagePage> {
thumbnail: WeChatImage.network(_thumnail), thumbnail: WeChatImage.network(_thumnail),
scene: scene, scene: scene,
); );
shareToWeChat(model); fluwx.share(model);
} }
void handleRadioValueChanged(WeChatScene scene) { void handleRadioValueChanged(WeChatScene scene) {
......
...@@ -6,10 +6,9 @@ class SignAutoDeductPage extends StatefulWidget { ...@@ -6,10 +6,9 @@ class SignAutoDeductPage extends StatefulWidget {
const SignAutoDeductPage({Key? key}) : super(key: key); const SignAutoDeductPage({Key? key}) : super(key: key);
@override @override
_SignAutoDeductPageState createState() => _SignAutoDeductPageState(); State<SignAutoDeductPage> createState() => _SignAutoDeductPageState();
} }
/// see wechat [document](https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_5&index=2)
class _SignAutoDeductPageState extends State<SignAutoDeductPage> { class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
TextEditingController appId = TextEditingController appId =
TextEditingController(text: 'wx316f9c82e99ac105'); TextEditingController(text: 'wx316f9c82e99ac105');
...@@ -25,10 +24,12 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> { ...@@ -25,10 +24,12 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
TextEditingController timestamp = TextEditingController(text: ''); TextEditingController timestamp = TextEditingController(text: '');
TextEditingController returnApp = TextEditingController(text: '3'); TextEditingController returnApp = TextEditingController(text: '3');
Fluwx fluwx = Fluwx();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
weChatResponseEventHandler.listen((resp) { fluwx.subscribeResponse((resp) {
print('resp = ${resp.isSuccessful}'); print('resp = ${resp.isSuccessful}');
}); });
} }
...@@ -54,10 +55,9 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> { ...@@ -54,10 +55,9 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('SubscribeMessagePage'), title: const Text('SubscribeMessagePage'),
), ),
body: Container( body: ListView(
child: ListView(
children: <Widget>[ children: <Widget>[
_buildTextField( _buildTextField(
title: 'appId', title: 'appId',
...@@ -109,7 +109,6 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> { ...@@ -109,7 +109,6 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
), ),
], ],
), ),
),
); );
} }
...@@ -124,7 +123,8 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> { ...@@ -124,7 +123,8 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
} }
void _signAutoDeduct() { void _signAutoDeduct() {
autoDeDuctWeChat( fluwx.autoDeduct(
data: AutoDeduct.detail(
appId: appId.text, appId: appId.text,
mchId: mchId.text, mchId: mchId.text,
planId: planId.text, planId: planId.text,
...@@ -136,6 +136,6 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> { ...@@ -136,6 +136,6 @@ class _SignAutoDeductPageState extends State<SignAutoDeductPage> {
sign: sign.text, sign: sign.text,
timestamp: timestamp.text, timestamp: timestamp.text,
returnApp: '3', returnApp: '3',
); ));
} }
} }
...@@ -5,7 +5,7 @@ class SubscribeMessagePage extends StatefulWidget { ...@@ -5,7 +5,7 @@ class SubscribeMessagePage extends StatefulWidget {
const SubscribeMessagePage({Key? key}) : super(key: key); const SubscribeMessagePage({Key? key}) : super(key: key);
@override @override
_SubscribeMessagePageState createState() => _SubscribeMessagePageState(); State<SubscribeMessagePage> createState() => _SubscribeMessagePageState();
} }
/// see wechat [document](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500434436_aWfqW&token=&lang=zh_CN) /// see wechat [document](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1500434436_aWfqW&token=&lang=zh_CN)
...@@ -16,12 +16,13 @@ class _SubscribeMessagePageState extends State<SubscribeMessagePage> { ...@@ -16,12 +16,13 @@ class _SubscribeMessagePageState extends State<SubscribeMessagePage> {
TextEditingController templateId = TextEditingController( TextEditingController templateId = TextEditingController(
text: 'cm_vM2k3IjHcYbkGUeAfL6Fja_7Pgv4Hx_q4tA253Ss'); text: 'cm_vM2k3IjHcYbkGUeAfL6Fja_7Pgv4Hx_q4tA253Ss');
TextEditingController reserved = TextEditingController(text: '123'); TextEditingController reserved = TextEditingController(text: '123');
Fluwx fluwx = Fluwx();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
weChatResponseEventHandler.listen((resp) { fluwx.subscribeResponse((resp) {
print('resp = $resp'); debugPrint('resp = $resp');
}); });
} }
...@@ -80,11 +81,12 @@ class _SubscribeMessagePageState extends State<SubscribeMessagePage> { ...@@ -80,11 +81,12 @@ class _SubscribeMessagePageState extends State<SubscribeMessagePage> {
} }
void _requestSubMsg() { void _requestSubMsg() {
subscribeWeChatMsg( fluwx.open(
target: SubscribeMessage(
appId: appId.text, appId: appId.text,
scene: int.tryParse(scene.text) ?? 1, scene: int.tryParse(scene.text) ?? 1,
templateId: templateId.text, templateId: templateId.text,
reserved: reserved.text, reserved: reserved.text,
); ));
} }
} }
name: fluwx_example name: fluwx_example
description: Demonstrates how to use the fluwx plugin. description: Demonstrates how to use the fluwx plugin.
publish_to: 'none' # The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
environment: environment:
sdk: ">=2.12.4 <3.0.0" sdk: '>=3.0.0 <4.0.0'
# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
characters: ^1.2.0
fluwx:
# When depending on this package from a real application you should use:
# fluwx: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.1+1 cupertino_icons: ^1.0.2
dev_dependencies: dev_dependencies:
integration_test:
sdk: flutter
flutter_test: flutter_test:
sdk: flutter sdk: flutter
fluwx: # The "flutter_lints" package below contains a set of recommended lints to
path: ../ # encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter. # The following section is specific to Flutter packages.
flutter: flutter:
# The following line ensures that the Material Icons font is # The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in # included with your application, so that you can use the icons in
# the material Icons class. # the material Icons class.
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets: assets:
- images/logo.png - images/logo.png
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware. # https://flutter.dev/assets-and-images/#resolution-aware
# For details regarding adding assets from package dependencies, see # For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages # https://flutter.dev/assets-and-images/#from-packages
...@@ -63,3 +82,15 @@ flutter: ...@@ -63,3 +82,15 @@ flutter:
# #
# For details regarding fonts from package dependencies, # For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages # see https://flutter.dev/custom-fonts/#from-packages
fluwx:
app_id: 123456
# only debug in debug mode
debug_logging: true
android:
# interrupt_wx_request: true # default is true
# flutter_activity: MainActivity #Default to launch app's launcher
ios:
universal_link: https://testdomain.com
# payment is enabled by default
# no_pay: true
// This is a basic Flutter widget test. // This is a basic Flutter widget test.
// //
// To perform an interaction with a widget in your test, use the WidgetTester // To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll // utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget // gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct. // tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_example/main.dart'; import 'package:fluwx_example/main.dart';
...@@ -12,15 +13,15 @@ import 'package:fluwx_example/main.dart'; ...@@ -12,15 +13,15 @@ import 'package:fluwx_example/main.dart';
void main() { void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async { testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(MyApp()); await tester.pumpWidget(const MyApp());
// Verify that platform version is retrieved. // Verify that platform version is retrieved.
// expect( expect(
// find.byWidgetPredicate( find.byWidgetPredicate(
// (Widget widget) => widget is Text && (Widget widget) => widget is Text &&
// widget.data.startsWith('Running on:'), widget.data!.startsWith('Running on:'),
// ), ),
// findsOneWidget, findsOneWidget,
// ); );
}); });
} }
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="Demonstrates how to use the fluwx plugin.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="fluwx_example">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>fluwx_example</title>
<link rel="manifest" href="manifest.json">
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;
</script>
<!-- This script adds the flutter initialization JS code -->
<script src="flutter.js" defer></script>
</head>
<body>
<script>
window.addEventListener('load', function(ev) {
// Download main.dart.js
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: function(engineInitializer) {
engineInitializer.initializeEngine().then(function(appRunner) {
appRunner.runApp();
});
}
});
});
</script>
</body>
</html>
{
"name": "fluwx_example",
"short_name": "fluwx_example",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "Demonstrates how to use the fluwx plugin.",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [
{
"src": "icons/Icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/Icon-512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "icons/Icon-maskable-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "icons/Icon-maskable-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
...@@ -34,6 +34,5 @@ Icon? ...@@ -34,6 +34,5 @@ Icon?
.tags* .tags*
/Flutter/Generated.xcconfig /Flutter/Generated.xcconfig
/Flutter/ephemeral/
/Flutter/flutter_export_environment.sh /Flutter/flutter_export_environment.sh
\ No newline at end of file
.gradle
\ No newline at end of file
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论