提交 ce275a5f authored 作者: guoqing's avatar guoqing

Initial commit

上级
# 3.9.0
* 支持微信卡包
# 3.8.5
* Fix #471
# 3.8.4+3
* Fix #478 #466 #470 #472
# 3.8.4+2
* Fix #472
# 3.8.4+1
* Fix #471
# 3.8.4
* 增加微信的日志开关
# 3.8.3
* Merge #457
# 3.8.2+1
* 升级kotlin-coroutine
# 3.8.2
* 新加自动订阅续费功能
# 3.8.1+1
* Just update docs
# 3.8.1
* 在iOS中增加FluwxDelegate
* 尝试修复iOS冷启动获取extMsg问题
# 3.8.0+3
* Fix #462
# 3.8.0+2
* Fix #461
# 3.8.0+1
* Fix #460
# 3.8.0
* APP调起支付分-订单详情
# 3.7.0
* Mirror of #455
# 3.6.1+6
* Fix #454
# 3.6.1+5
* Support Android P
# 3.6.1+4
* Fix #431
# 3.6.1+3
* Fix #422
# 3.6.1+2
* APP拉起微信客服功能
# 3.6.1+1
* Fix #419
* Fix #414
# 3.6.1
* Fix #416
# 3.6.0
* APP拉起微信客服功能
# 3.5.1
* 自动释放extMsg
# 3.5.0
* update compileSdkVersion
# 3.4.4
* update android sdk version
# 3.4.3
* Merge #370
# 3.4.2
* 修复Android编译问题
# 3.4.1
* 修复从外部拉起App白屏问题
* 修复从外部拉起App无法传值问题
# 3.4.0
* 修复从外部拉起App白屏问题
* 修复从外部拉起App无法传值问题
# 3.2.2
* Fix #357
# 3.2.1
* Fix #354
# 3.2.0
* Null-safety
* Fix #350
## 3.1.2-nullsafety.1
* Fix #338
## 3.1.1-nullsafety.1
* Fix #338
## 3.1.0-nullsafety.3
* Nothing
## 3.1.0-nullsafety.2
* Nothing
## 3.1.0-nullsafety.1
* Android支持通过H5冷启动app传递<wx-open-launch-app>中的extinfo数据
* Android新加<meta-data>handleWeChatRequestByFluwx</meta-data>
## 3.0.0-nullsafety.2
* Fix trailing , issue
## 3.0.0-nullsafety.1
* Support nullsafety
## 2.4.0
* App获取开放标签<wx-open-launch-app>中的extinfo数据
## 2.3.2
* Fix #317
## 2.3.1
* 修复Android 11分享图片问题
## 2.3.0
* 支持compressThumbnail
* 升级OkHttp
## 2.2.0
*兼容Flutter 1.20
*一些依赖升级
## 2.1.1
* Specifying supported platforms
* Fix: Android分享小程序时,缩略图压缩过重的问题
* 更改分享文件的实现形式
# 2.1.0
* WeChatSDK updates
# 2.0.4
* Fix #223
## 2.0.3+1
* Merge #218
## 2.0.3
* Fix #212
## 2.0.1+2
* Fix: Android分享大图时存储权限问题
## 2.0.1+1
* Fix: Android请求权限崩溃的问题
## 2.0.1
* Fix: Android请求权限崩溃的问题
## 2.0.0
* 按照pub建议改进
* 代码重构,现在代码结构更清晰
* 所有图片由WeChatImage构建
* 现在iOS对分享微信小程序的高清图也会压缩
* 微信回调监听形式变更
* Android增加新的Action以防微信打开小程序出错不会返回原app的问题
* iOS改用Pod引用微信SDK
* iOS隐藏一些header
* kotlin 1.3.70
## 1.0.0
* Initial Release.
\ No newline at end of file
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# Fluwx
![pub package](https://img.shields.io/pub/v/fluwx.svg)
![Build status](https://github.com/OpenFlutter/fluwx/actions/workflows/build_test.yml/badge.svg)
======
![logo](https://gitee.com/OpenFlutter/resoures-repository/raw/master/fluwx/fluwx_logo.png)
[中文请移步此处](./README_CN.md)
## What's Fluwx
`Fluwx` is flutter plugin for [WeChatSDK](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Resource_Center_Homepage.html) which allows developers to call
[WeChatSDK](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Resource_Center_Homepage.html) native APIs.
> Join QQ Group now: 1003811176
![QQGroup](https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/flutter.png)
## Capability
- Share images, texts, music and so on to WeChat, including session, favorite and timeline.
- Payment with WeChat.
- Get auth code before you login in with WeChat.
- Launch mini program in WeChat.
- Subscribe Message.
- Just open WeChat app.
- Launch app From wechat link.
## Preparation
`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.
[Watch Charged Video](https://study.163.com/course/introduction.htm?share=2&shareId=480000001896427&courseId=1209174838&_trace_c_p_k2_=e72467dc0df540579287a8ea996344a4)
## Install
Add the following dependencies in your `pubspec.yaml` file:
`Fluwx` with pay:
```yaml
dependencies:
fluwx: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx.svg)
`Fluwx` without pay:
```yaml
dependencies:
fluwx_no_pay: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)
> NOTE: Never forget to replace ^${latestVersion} with actual version.
## Register WxAPI
Register your app via `fluwx` if necessary.
```dart
registerWxApi(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
how to create universalLink. You can also learn how to add URL schema, how to add `LSApplicationQueriesSchemes` in your iOS project. This is essential.
For Android, you shall know to how generate signature for your app in [this page](https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html).
And you have to understand the difference between debug signature and release signature. Once the signature is incorrect, then you'll get `errCode = -1`.
## Capability Document
- [Basic knowledge](./doc/BASIC_KNOWLEDGE.md)
- [Share](./doc/SHARE.md)
- [Payment](./doc/PAYMENT.md)
- [Auth](./doc/AUTH.md)
- [Launch app from h5](./doc/LAUNCH_APP_FROM_H5.md)
For more capabilities, you can read the public functions of `fluwx`.
## QA
[These questions maybe help](./doc/QA_CN.md)
## Donate
Buy the writer a cup of coffee。
<img src="https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/wx.jpeg" height="300"> <img src="https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/ali.jpeg" height="300">
## Subscribe Us On WeChat
![subscribe](https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/wx_subscription.png)
## LICENSE
Copyright 2018 OpenFlutter Project
Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for
additional information regarding copyright ownership. The ASF licenses this
file to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
# Fluwx
![pub package](https://img.shields.io/pub/v/fluwx.svg)
![Build status](https://github.com/OpenFlutter/fluwx/actions/workflows/build_test.yml/badge.svg)
======
![logo](https://gitee.com/OpenFlutter/resoures-repository/raw/master/fluwx/fluwx_logo.png)
## 什么是Fluwx
`Fluwx` 是一个[微信SDK](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Resource_Center_Homepage.html)插件,它允许开发者调用
[微信原生SDK ](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Resource_Center_Homepage.html).
> 加入我们的QQ群: 1003811176
![QQGroup](https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/flutter.png)
## 能力
- 分享图片,文本,音乐,视频等。支持分享到会话,朋友圈以及收藏.
- 微信支付.
- 在微信登录时,获取Auth Code.
- 拉起小程序.
- 订阅消息.
- 打开微信.
- 从微信标签打开应用
## 准备
`Fluwx` 可以做很多工作但不是所有. 在集成之前,最好读一下[官方文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1).
然后你才知道怎么生成签名,怎么使用universal link以及怎么添加URL schema等.
> [收费视频教程点这里](https://study.163.com/course/introduction.htm?share=2&shareId=480000001896427&courseId=1209174838&_trace_c_p_k2_=e72467dc0df540579287a8ea996344a4)
>
## 安装
`pubspec.yaml` 文件中添加`fluwx`依赖:
`Fluwx`,带支付:
```yaml
dependencies:
fluwx: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx.svg)
`Fluwx`,不带支付:
```yaml
dependencies:
fluwx_no_pay: ^${latestVersion}
```
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)
> NOTE: 别忘记替换 ^${latestVersion} !!!!
## 注册 WxAPI
通过 `fluwx` 注册WxApi.
```dart
registerWxApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/");
```
参数 `universalLink` 只在iOS上有用. 查看[文档](https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html) 以便了解如何生成通用链接.
你也可以学习到怎么在iOS工程中添加URL schema,怎么添加`LSApplicationQueriesSchemes`。这很重要。
对于Android, 可以查看[本文](https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html)以便了解怎么获取app签名.
然后你需要知道release和debug时,app签名有什么区别。如果签名不对,你会得一个错误 `errCode = -1`.
## 能力文档
- [基础知识](./doc/BASIC_KNOWLEDGE_CN.md)
- [分享](./doc/SHARE_CN.md)
- [支付](./doc/PAYMENT_CN.md)
- [登录](./doc/AUTH_CN.md)
- [从微信标签打开应用](./doc/LAUNCH_APP_FROM_H5_CN.md)
对于更多功能,可以查看源码。
## QA
[这些问题可能对你有帮助](./doc/QA_CN.md)
## 捐助
开源不易,请作者喝杯咖啡。
<img src="https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/wx.jpeg" height="300"> <img src="https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/ali.jpeg" height="300">
## 关注公众号
![subscribe](https://gitee.com/OpenFlutter/resoures-repository/raw/master/common/wx_subscription.png)
## LICENSE
Copyright 2018 OpenFlutter Project
Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for
additional information regarding copyright ownership. The ASF licenses this
file to you under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
group 'com.jarvan.fluwx'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.6.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 30
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 16
consumerProguardFiles 'consumer-proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}
dependencies {
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:6.8.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
implementation 'id.zelory:compressor:3.0.1'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
testImplementation 'junit:junit:4.13.2'
}
\ No newline at end of file
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.jarvan.fluwx;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String LIBRARY_PACKAGE_NAME = "com.jarvan.fluwx";
public static final String BUILD_TYPE = "debug";
}
/**
* Automatically generated file. DO NOT MODIFY
*/
package com.jarvan.fluwx;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String LIBRARY_PACKAGE_NAME = "com.jarvan.fluwx";
public static final String BUILD_TYPE = "release";
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jarvan.fluwx" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Support WeChat query on Android P -->
<queries>
<package android:name="com.tencent.mm" />
</queries>
<application>
<activity
android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:exported="false"
android:launchMode="singleTask"
android:taskAffinity="dollar_openBracket_applicationId_closeBracket"
android:theme="@style/DisablePreviewTheme" />
<activity-alias
android:name="dollar_openBracket_applicationId_closeBracket.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<activity-alias
android:name="dollar_openBracket_applicationId_closeBracket.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="dollar_openBracket_applicationId_closeBracket"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<provider
android:name="com.jarvan.fluwx.FluwxFileProvider"
android:authorities="dollar_openBracket_applicationId_closeBracket.fluwxprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fluwx_file_provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "AAPT_FRIENDLY_MERGED_MANIFESTS",
"kind": "Directory"
},
"applicationId": "com.jarvan.fluwx",
"variantName": "debug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"outputFile": "AndroidManifest.xml"
}
],
"elementType": "File"
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jarvan.fluwx" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Support WeChat query on Android P -->
<queries>
<package android:name="com.tencent.mm" />
</queries>
<application>
<activity
android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:exported="false"
android:launchMode="singleTask"
android:taskAffinity="dollar_openBracket_applicationId_closeBracket"
android:theme="@style/DisablePreviewTheme" />
<activity-alias
android:name="dollar_openBracket_applicationId_closeBracket.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<activity-alias
android:name="dollar_openBracket_applicationId_closeBracket.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="dollar_openBracket_applicationId_closeBracket"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<provider
android:name="com.jarvan.fluwx.FluwxFileProvider"
android:authorities="dollar_openBracket_applicationId_closeBracket.fluwxprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fluwx_file_provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "AAPT_FRIENDLY_MERGED_MANIFESTS",
"kind": "Directory"
},
"applicationId": "com.jarvan.fluwx",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"outputFile": "AndroidManifest.xml"
}
],
"elementType": "File"
}
\ No newline at end of file
aarFormatVersion=1.0
aarMetadataVersion=1.0
minCompileSdk=1
minAndroidGradlePluginVersion=1.0.0
aarFormatVersion=1.0
aarMetadataVersion=1.0
minCompileSdk=1
minAndroidGradlePluginVersion=1.0.0
int attr activityAction 0x0
int attr activityName 0x0
int attr alpha 0x0
int attr alwaysExpand 0x0
int attr clearTop 0x0
int attr finishPrimaryWithSecondary 0x0
int attr finishSecondaryWithPrimary 0x0
int attr font 0x0
int attr fontProviderAuthority 0x0
int attr fontProviderCerts 0x0
int attr fontProviderFetchStrategy 0x0
int attr fontProviderFetchTimeout 0x0
int attr fontProviderPackage 0x0
int attr fontProviderQuery 0x0
int attr fontProviderSystemFontFamily 0x0
int attr fontStyle 0x0
int attr fontVariationSettings 0x0
int attr fontWeight 0x0
int attr nestedScrollViewStyle 0x0
int attr placeholderActivityName 0x0
int attr primaryActivityName 0x0
int attr queryPatterns 0x0
int attr secondaryActivityAction 0x0
int attr secondaryActivityName 0x0
int attr shortcutMatchRequired 0x0
int attr splitLayoutDirection 0x0
int attr splitMinSmallestWidth 0x0
int attr splitMinWidth 0x0
int attr splitRatio 0x0
int attr ttcIndex 0x0
int color androidx_core_ripple_material_light 0x0
int color androidx_core_secondary_text_default_material_light 0x0
int color notification_action_color_filter 0x0
int color notification_icon_bg_color 0x0
int color ripple_material_light 0x0
int color secondary_text_default_material_light 0x0
int dimen compat_button_inset_horizontal_material 0x0
int dimen compat_button_inset_vertical_material 0x0
int dimen compat_button_padding_horizontal_material 0x0
int dimen compat_button_padding_vertical_material 0x0
int dimen compat_control_corner_material 0x0
int dimen compat_notification_large_icon_max_height 0x0
int dimen compat_notification_large_icon_max_width 0x0
int dimen notification_action_icon_size 0x0
int dimen notification_action_text_size 0x0
int dimen notification_big_circle_margin 0x0
int dimen notification_content_margin_start 0x0
int dimen notification_large_icon_height 0x0
int dimen notification_large_icon_width 0x0
int dimen notification_main_column_padding_top 0x0
int dimen notification_media_narrow_margin 0x0
int dimen notification_right_icon_size 0x0
int dimen notification_right_side_padding_top 0x0
int dimen notification_small_icon_background_padding 0x0
int dimen notification_small_icon_size_as_large 0x0
int dimen notification_subtext_size 0x0
int dimen notification_top_pad 0x0
int dimen notification_top_pad_large_text 0x0
int drawable notification_action_background 0x0
int drawable notification_bg 0x0
int drawable notification_bg_low 0x0
int drawable notification_bg_low_normal 0x0
int drawable notification_bg_low_pressed 0x0
int drawable notification_bg_normal 0x0
int drawable notification_bg_normal_pressed 0x0
int drawable notification_icon_background 0x0
int drawable notification_template_icon_bg 0x0
int drawable notification_template_icon_low_bg 0x0
int drawable notification_tile_bg 0x0
int drawable notify_panel_notification_icon_bg 0x0
int id accessibility_action_clickable_span 0x0
int id accessibility_custom_action_0 0x0
int id accessibility_custom_action_1 0x0
int id accessibility_custom_action_10 0x0
int id accessibility_custom_action_11 0x0
int id accessibility_custom_action_12 0x0
int id accessibility_custom_action_13 0x0
int id accessibility_custom_action_14 0x0
int id accessibility_custom_action_15 0x0
int id accessibility_custom_action_16 0x0
int id accessibility_custom_action_17 0x0
int id accessibility_custom_action_18 0x0
int id accessibility_custom_action_19 0x0
int id accessibility_custom_action_2 0x0
int id accessibility_custom_action_20 0x0
int id accessibility_custom_action_21 0x0
int id accessibility_custom_action_22 0x0
int id accessibility_custom_action_23 0x0
int id accessibility_custom_action_24 0x0
int id accessibility_custom_action_25 0x0
int id accessibility_custom_action_26 0x0
int id accessibility_custom_action_27 0x0
int id accessibility_custom_action_28 0x0
int id accessibility_custom_action_29 0x0
int id accessibility_custom_action_3 0x0
int id accessibility_custom_action_30 0x0
int id accessibility_custom_action_31 0x0
int id accessibility_custom_action_4 0x0
int id accessibility_custom_action_5 0x0
int id accessibility_custom_action_6 0x0
int id accessibility_custom_action_7 0x0
int id accessibility_custom_action_8 0x0
int id accessibility_custom_action_9 0x0
int id action_container 0x0
int id action_divider 0x0
int id action_image 0x0
int id action_text 0x0
int id actions 0x0
int id androidx_window_activity_scope 0x0
int id async 0x0
int id blocking 0x0
int id chronometer 0x0
int id dialog_button 0x0
int id forever 0x0
int id icon 0x0
int id icon_group 0x0
int id info 0x0
int id italic 0x0
int id line1 0x0
int id line3 0x0
int id locale 0x0
int id ltr 0x0
int id normal 0x0
int id notification_background 0x0
int id notification_main_column 0x0
int id notification_main_column_container 0x0
int id right_icon 0x0
int id right_side 0x0
int id rtl 0x0
int id tag_accessibility_actions 0x0
int id tag_accessibility_clickable_spans 0x0
int id tag_accessibility_heading 0x0
int id tag_accessibility_pane_title 0x0
int id tag_on_apply_window_listener 0x0
int id tag_on_receive_content_listener 0x0
int id tag_on_receive_content_mime_types 0x0
int id tag_screen_reader_focusable 0x0
int id tag_state_description 0x0
int id tag_transition_group 0x0
int id tag_unhandled_key_event_manager 0x0
int id tag_unhandled_key_listeners 0x0
int id tag_window_insets_animation_callback 0x0
int id text 0x0
int id text2 0x0
int id time 0x0
int id title 0x0
int integer status_bar_notification_info_maxnum 0x0
int layout custom_dialog 0x0
int layout notification_action 0x0
int layout notification_action_tombstone 0x0
int layout notification_template_custom_big 0x0
int layout notification_template_icon_group 0x0
int layout notification_template_part_chronometer 0x0
int layout notification_template_part_time 0x0
int string status_bar_notification_info_overflow 0x0
int style DisablePreviewTheme 0x0
int style TextAppearance_Compat_Notification 0x0
int style TextAppearance_Compat_Notification_Info 0x0
int style TextAppearance_Compat_Notification_Line2 0x0
int style TextAppearance_Compat_Notification_Time 0x0
int style TextAppearance_Compat_Notification_Title 0x0
int style Widget_Compat_NotificationActionContainer 0x0
int style Widget_Compat_NotificationActionText 0x0
int[] styleable ActivityFilter { 0x0, 0x0 }
int styleable ActivityFilter_activityAction 0
int styleable ActivityFilter_activityName 1
int[] styleable ActivityRule { 0x0 }
int styleable ActivityRule_alwaysExpand 0
int[] styleable Capability { 0x0, 0x0 }
int styleable Capability_queryPatterns 0
int styleable Capability_shortcutMatchRequired 1
int[] styleable ColorStateListItem { 0x0, 0x101031f, 0x10101a5 }
int styleable ColorStateListItem_alpha 0
int styleable ColorStateListItem_android_alpha 1
int styleable ColorStateListItem_android_color 2
int[] styleable FontFamily { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
int styleable FontFamily_fontProviderAuthority 0
int styleable FontFamily_fontProviderCerts 1
int styleable FontFamily_fontProviderFetchStrategy 2
int styleable FontFamily_fontProviderFetchTimeout 3
int styleable FontFamily_fontProviderPackage 4
int styleable FontFamily_fontProviderQuery 5
int styleable FontFamily_fontProviderSystemFontFamily 6
int[] styleable FontFamilyFont { 0x1010532, 0x101053f, 0x1010570, 0x1010533, 0x101056f, 0x0, 0x0, 0x0, 0x0, 0x0 }
int styleable FontFamilyFont_android_font 0
int styleable FontFamilyFont_android_fontStyle 1
int styleable FontFamilyFont_android_fontVariationSettings 2
int styleable FontFamilyFont_android_fontWeight 3
int styleable FontFamilyFont_android_ttcIndex 4
int styleable FontFamilyFont_font 5
int styleable FontFamilyFont_fontStyle 6
int styleable FontFamilyFont_fontVariationSettings 7
int styleable FontFamilyFont_fontWeight 8
int styleable FontFamilyFont_ttcIndex 9
int[] styleable GradientColor { 0x101020b, 0x10101a2, 0x10101a3, 0x101019e, 0x1010512, 0x1010513, 0x10101a4, 0x101019d, 0x1010510, 0x1010511, 0x1010201, 0x10101a1 }
int styleable GradientColor_android_centerColor 0
int styleable GradientColor_android_centerX 1
int styleable GradientColor_android_centerY 2
int styleable GradientColor_android_endColor 3
int styleable GradientColor_android_endX 4
int styleable GradientColor_android_endY 5
int styleable GradientColor_android_gradientRadius 6
int styleable GradientColor_android_startColor 7
int styleable GradientColor_android_startX 8
int styleable GradientColor_android_startY 9
int styleable GradientColor_android_tileMode 10
int styleable GradientColor_android_type 11
int[] styleable GradientColorItem { 0x10101a5, 0x1010514 }
int styleable GradientColorItem_android_color 0
int styleable GradientColorItem_android_offset 1
int[] styleable SplitPairFilter { 0x0, 0x0, 0x0 }
int styleable SplitPairFilter_primaryActivityName 0
int styleable SplitPairFilter_secondaryActivityAction 1
int styleable SplitPairFilter_secondaryActivityName 2
int[] styleable SplitPairRule { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }
int styleable SplitPairRule_clearTop 0
int styleable SplitPairRule_finishPrimaryWithSecondary 1
int styleable SplitPairRule_finishSecondaryWithPrimary 2
int styleable SplitPairRule_splitLayoutDirection 3
int styleable SplitPairRule_splitMinSmallestWidth 4
int styleable SplitPairRule_splitMinWidth 5
int styleable SplitPairRule_splitRatio 6
int[] styleable SplitPlaceholderRule { 0x0, 0x0, 0x0, 0x0, 0x0 }
int styleable SplitPlaceholderRule_placeholderActivityName 0
int styleable SplitPlaceholderRule_splitLayoutDirection 1
int styleable SplitPlaceholderRule_splitMinSmallestWidth 2
int styleable SplitPlaceholderRule_splitMinWidth 3
int styleable SplitPlaceholderRule_splitRatio 4
int xml fluwx_file_provider_paths 0x0
#Wed Jul 20 16:15:08 CST 2022
com.jarvan.fluwx.fluwx_no_pay-main-7\:/xml/fluwx_file_provider_paths.xml=/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/packaged_res/debug/xml/fluwx_file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/debug"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"><file path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/values/styles.xml" qualifiers=""><style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style></file><file name="fluwx_file_provider_paths" path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml" qualifiers="" type="xml"/></source><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/debug"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug" generated-set="debug$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/res"/></dataSet><mergedItems/></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/jniLibs"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/jniLibs"/></dataSet></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/shaders"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/shaders"/></dataSet></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/jniLibs"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/jniLibs"/></dataSet></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/shaders"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/shaders"/></dataSet></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/assets"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/shader_assets/debug/out"/></dataSet><dataSet config="debug" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/assets"/></dataSet></merger>
\ No newline at end of file
#Wed Jul 20 16:08:53 CST 2022
/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml=/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/packaged_res/debug/xml/fluwx_file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/debug"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"><file path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/values/styles.xml" qualifiers=""><style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style></file><file name="fluwx_file_provider_paths" path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml" qualifiers="" type="xml"/></source><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/debug"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/debug"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="debug" generated-set="debug$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/debug/res"/></dataSet><mergedItems/></merger>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/assets"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/shader_assets/release/out"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/assets"/></dataSet></merger>
\ No newline at end of file
#Wed Jul 20 16:10:23 CST 2022
/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml=/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/packaged_res/release/xml/fluwx_file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/release"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"><file path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/values/styles.xml" qualifiers=""><style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style></file><file name="fluwx_file_provider_paths" path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml" qualifiers="" type="xml"/></source><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/release"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release" generated-set="release$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/res"/></dataSet><mergedItems/></merger>
\ No newline at end of file
#Wed Jul 20 16:15:20 CST 2022
com.jarvan.fluwx.fluwx_no_pay-main-6\:/xml/fluwx_file_provider_paths.xml=/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/intermediates/packaged_res/release/xml/fluwx_file_provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/release"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res"><file path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/values/styles.xml" qualifiers=""><style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style></file><file name="fluwx_file_provider_paths" path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/res/xml/fluwx_file_provider_paths.xml" qualifiers="" type="xml"/></source><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/rs/release"/><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release" generated-set="release$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/release/res"/></dataSet><mergedItems/></merger>
\ No newline at end of file
R_DEF: Internal format may change without notice
local
style DisablePreviewTheme
xml fluwx_file_provider_paths
R_DEF: Internal format may change without notice
local
style DisablePreviewTheme
xml fluwx_file_provider_paths
1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.jarvan.fluwx" >
4
5 <uses-sdk
6 android:minSdkVersion="16"
6-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
7 android:targetSdkVersion="16" />
7-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
8
9 <uses-permission android:name="android.permission.INTERNET" />
9-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:5-67
9-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:22-64
10 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
10-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:5-79
10-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:22-76
11 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
11-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:5-76
11-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:22-73
12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
12-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:5-81
12-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:22-78
13
14 <!-- Support WeChat query on Android P -->
15 <queries>
15-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:10:5-12:15
16 <package android:name="com.tencent.mm" />
16-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:9-50
16-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:18-47
17 </queries>
18
19 <application>
19-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:14:5-60:19
20 <activity
20-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:15:9-20:58
21 android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
21-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:16:13-55
22 android:exported="false"
22-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:18:13-37
23 android:launchMode="singleTask"
23-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:17:13-44
24 android:taskAffinity="${applicationId}"
24-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:19:13-52
25 android:theme="@style/DisablePreviewTheme" />
25-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:20:13-55
26
27 <activity-alias
27-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:36:9-49:26
28 android:name="${applicationId}.wxapi.WXPayEntryActivity"
28-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:37:13-69
29 android:exported="true"
29-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:38:13-36
30 android:launchMode="singleInstance"
30-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:39:13-48
31 android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
31-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:40:13-81
32 android:theme="@style/DisablePreviewTheme" >
32-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:41:13-55
33 <intent-filter>
33-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
34 <action android:name="android.intent.action.VIEW" />
34-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
34-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
35
36 <category android:name="android.intent.category.DEFAULT" />
36-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
36-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
37
38 <data android:scheme="sdksample" />
38-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
38-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
39 </intent-filter>
40 </activity-alias>
41 <activity-alias
41-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:22:9-35:26
42 android:name="${applicationId}.wxapi.WXEntryActivity"
42-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:23:13-66
43 android:exported="true"
43-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:24:13-36
44 android:launchMode="singleTop"
44-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:25:13-43
45 android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
45-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:26:13-81
46 android:taskAffinity="${applicationId}"
46-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:27:13-52
47 android:theme="@style/DisablePreviewTheme" >
47-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:28:13-55
48 <intent-filter>
48-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
49 <action android:name="android.intent.action.VIEW" />
49-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
49-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
50
51 <category android:name="android.intent.category.DEFAULT" />
51-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
51-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
52
53 <data android:scheme="sdksample" />
53-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
53-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
54 </intent-filter>
55 </activity-alias>
56
57 <provider
57-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:51:9-59:20
58 android:name="com.jarvan.fluwx.FluwxFileProvider"
58-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:52:13-62
59 android:authorities="${applicationId}.fluwxprovider"
59-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:53:13-65
60 android:exported="false"
60-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:54:13-37
61 android:grantUriPermissions="true" >
61-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:55:13-47
62 <meta-data
62-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:56:13-58:69
63 android:name="android.support.FILE_PROVIDER_PATHS"
63-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:57:17-67
64 android:resource="@xml/fluwx_file_provider_paths" />
64-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:58:17-66
65 </provider>
66 </application>
67
68</manifest>
1<?xml version="1.0" encoding="utf-8"?>
2<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3 package="com.jarvan.fluwx" >
4
5 <uses-sdk
6 android:minSdkVersion="16"
6-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
7 android:targetSdkVersion="16" />
7-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
8
9 <uses-permission android:name="android.permission.INTERNET" />
9-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:5-67
9-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:22-64
10 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
10-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:5-79
10-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:22-76
11 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
11-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:5-76
11-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:22-73
12 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
12-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:5-81
12-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:22-78
13
14 <!-- Support WeChat query on Android P -->
15 <queries>
15-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:10:5-12:15
16 <package android:name="com.tencent.mm" />
16-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:9-50
16-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:18-47
17 </queries>
18
19 <application>
19-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:14:5-60:19
20 <activity
20-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:15:9-20:58
21 android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
21-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:16:13-55
22 android:exported="false"
22-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:18:13-37
23 android:launchMode="singleTask"
23-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:17:13-44
24 android:taskAffinity="${applicationId}"
24-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:19:13-52
25 android:theme="@style/DisablePreviewTheme" />
25-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:20:13-55
26
27 <activity-alias
27-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:36:9-49:26
28 android:name="${applicationId}.wxapi.WXPayEntryActivity"
28-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:37:13-69
29 android:exported="true"
29-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:38:13-36
30 android:launchMode="singleInstance"
30-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:39:13-48
31 android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
31-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:40:13-81
32 android:theme="@style/DisablePreviewTheme" >
32-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:41:13-55
33 <intent-filter>
33-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
34 <action android:name="android.intent.action.VIEW" />
34-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
34-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
35
36 <category android:name="android.intent.category.DEFAULT" />
36-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
36-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
37
38 <data android:scheme="sdksample" />
38-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
38-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
39 </intent-filter>
40 </activity-alias>
41 <activity-alias
41-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:22:9-35:26
42 android:name="${applicationId}.wxapi.WXEntryActivity"
42-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:23:13-66
43 android:exported="true"
43-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:24:13-36
44 android:launchMode="singleTop"
44-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:25:13-43
45 android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
45-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:26:13-81
46 android:taskAffinity="${applicationId}"
46-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:27:13-52
47 android:theme="@style/DisablePreviewTheme" >
47-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:28:13-55
48 <intent-filter>
48-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
49 <action android:name="android.intent.action.VIEW" />
49-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
49-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
50
51 <category android:name="android.intent.category.DEFAULT" />
51-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
51-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
52
53 <data android:scheme="sdksample" />
53-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
53-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
54 </intent-filter>
55 </activity-alias>
56
57 <provider
57-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:51:9-59:20
58 android:name="com.jarvan.fluwx.FluwxFileProvider"
58-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:52:13-62
59 android:authorities="${applicationId}.fluwxprovider"
59-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:53:13-65
60 android:exported="false"
60-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:54:13-37
61 android:grantUriPermissions="true" >
61-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:55:13-47
62 <meta-data
62-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:56:13-58:69
63 android:name="android.support.FILE_PROVIDER_PATHS"
63-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:57:17-67
64 android:resource="@xml/fluwx_file_provider_paths" />
64-->/Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:58:17-66
65 </provider>
66 </application>
67
68</manifest>
# 微信
-keep class com.tencent.mm.opensdk.** {*;}
-keep class com.tencent.wxop.** {*;}
-keep class com.tencent.mm.sdk.** {*;}
## Kotlin
# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jarvan.fluwx" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Support WeChat query on Android P -->
<queries>
<package android:name="com.tencent.mm" />
</queries>
<application>
<activity
android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:exported="false"
android:launchMode="singleTask"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" />
<activity-alias
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<activity-alias
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<provider
android:name="com.jarvan.fluwx.FluwxFileProvider"
android:authorities="${applicationId}.fluwxprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fluwx_file_provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jarvan.fluwx" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="16" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Support WeChat query on Android P -->
<queries>
<package android:name="com.tencent.mm" />
</queries>
<application>
<activity
android:name="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:exported="false"
android:launchMode="singleTask"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" />
<activity-alias
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<activity-alias
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<provider
android:name="com.jarvan.fluwx.FluwxFileProvider"
android:authorities="${applicationId}.fluwxprovider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fluwx_file_provider_paths" />
</provider>
</application>
</manifest>
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "PACKAGED_MANIFESTS",
"kind": "Directory"
},
"applicationId": "com.jarvan.fluwx",
"variantName": "debug",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"outputFile": "../../merged_manifest/debug/AndroidManifest.xml"
}
],
"elementType": "File"
}
\ No newline at end of file
{
"version": 3,
"artifactType": {
"type": "PACKAGED_MANIFESTS",
"kind": "Directory"
},
"applicationId": "com.jarvan.fluwx",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"outputFile": "../../merged_manifest/release/AndroidManifest.xml"
}
],
"elementType": "File"
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="fluwxSharedData" path="fluwxSharedData/"/>
</paths>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="fluwxSharedData" path="fluwxSharedData/"/>
</paths>
\ No newline at end of file
com.jarvan.fluwx
attr activityAction
attr activityName
attr alpha
attr alwaysExpand
attr clearTop
attr finishPrimaryWithSecondary
attr finishSecondaryWithPrimary
attr font
attr fontProviderAuthority
attr fontProviderCerts
attr fontProviderFetchStrategy
attr fontProviderFetchTimeout
attr fontProviderPackage
attr fontProviderQuery
attr fontProviderSystemFontFamily
attr fontStyle
attr fontVariationSettings
attr fontWeight
attr nestedScrollViewStyle
attr placeholderActivityName
attr primaryActivityName
attr queryPatterns
attr secondaryActivityAction
attr secondaryActivityName
attr shortcutMatchRequired
attr splitLayoutDirection
attr splitMinSmallestWidth
attr splitMinWidth
attr splitRatio
attr ttcIndex
color androidx_core_ripple_material_light
color androidx_core_secondary_text_default_material_light
color notification_action_color_filter
color notification_icon_bg_color
color ripple_material_light
color secondary_text_default_material_light
dimen compat_button_inset_horizontal_material
dimen compat_button_inset_vertical_material
dimen compat_button_padding_horizontal_material
dimen compat_button_padding_vertical_material
dimen compat_control_corner_material
dimen compat_notification_large_icon_max_height
dimen compat_notification_large_icon_max_width
dimen notification_action_icon_size
dimen notification_action_text_size
dimen notification_big_circle_margin
dimen notification_content_margin_start
dimen notification_large_icon_height
dimen notification_large_icon_width
dimen notification_main_column_padding_top
dimen notification_media_narrow_margin
dimen notification_right_icon_size
dimen notification_right_side_padding_top
dimen notification_small_icon_background_padding
dimen notification_small_icon_size_as_large
dimen notification_subtext_size
dimen notification_top_pad
dimen notification_top_pad_large_text
drawable notification_action_background
drawable notification_bg
drawable notification_bg_low
drawable notification_bg_low_normal
drawable notification_bg_low_pressed
drawable notification_bg_normal
drawable notification_bg_normal_pressed
drawable notification_icon_background
drawable notification_template_icon_bg
drawable notification_template_icon_low_bg
drawable notification_tile_bg
drawable notify_panel_notification_icon_bg
id accessibility_action_clickable_span
id accessibility_custom_action_0
id accessibility_custom_action_1
id accessibility_custom_action_10
id accessibility_custom_action_11
id accessibility_custom_action_12
id accessibility_custom_action_13
id accessibility_custom_action_14
id accessibility_custom_action_15
id accessibility_custom_action_16
id accessibility_custom_action_17
id accessibility_custom_action_18
id accessibility_custom_action_19
id accessibility_custom_action_2
id accessibility_custom_action_20
id accessibility_custom_action_21
id accessibility_custom_action_22
id accessibility_custom_action_23
id accessibility_custom_action_24
id accessibility_custom_action_25
id accessibility_custom_action_26
id accessibility_custom_action_27
id accessibility_custom_action_28
id accessibility_custom_action_29
id accessibility_custom_action_3
id accessibility_custom_action_30
id accessibility_custom_action_31
id accessibility_custom_action_4
id accessibility_custom_action_5
id accessibility_custom_action_6
id accessibility_custom_action_7
id accessibility_custom_action_8
id accessibility_custom_action_9
id action_container
id action_divider
id action_image
id action_text
id actions
id androidx_window_activity_scope
id async
id blocking
id chronometer
id dialog_button
id forever
id icon
id icon_group
id info
id italic
id line1
id line3
id locale
id ltr
id normal
id notification_background
id notification_main_column
id notification_main_column_container
id right_icon
id right_side
id rtl
id tag_accessibility_actions
id tag_accessibility_clickable_spans
id tag_accessibility_heading
id tag_accessibility_pane_title
id tag_on_apply_window_listener
id tag_on_receive_content_listener
id tag_on_receive_content_mime_types
id tag_screen_reader_focusable
id tag_state_description
id tag_transition_group
id tag_unhandled_key_event_manager
id tag_unhandled_key_listeners
id tag_window_insets_animation_callback
id text
id text2
id time
id title
integer status_bar_notification_info_maxnum
layout custom_dialog
layout notification_action
layout notification_action_tombstone
layout notification_template_custom_big
layout notification_template_icon_group
layout notification_template_part_chronometer
layout notification_template_part_time
string status_bar_notification_info_overflow
style DisablePreviewTheme
style TextAppearance_Compat_Notification
style TextAppearance_Compat_Notification_Info
style TextAppearance_Compat_Notification_Line2
style TextAppearance_Compat_Notification_Time
style TextAppearance_Compat_Notification_Title
style Widget_Compat_NotificationActionContainer
style Widget_Compat_NotificationActionText
styleable ActivityFilter activityAction activityName
styleable ActivityRule alwaysExpand
styleable Capability queryPatterns shortcutMatchRequired
styleable ColorStateListItem alpha android_alpha android_color
styleable FontFamily fontProviderAuthority fontProviderCerts fontProviderFetchStrategy fontProviderFetchTimeout fontProviderPackage fontProviderQuery fontProviderSystemFontFamily
styleable FontFamilyFont android_font android_fontStyle android_fontVariationSettings android_fontWeight android_ttcIndex font fontStyle fontVariationSettings fontWeight ttcIndex
styleable GradientColor android_centerColor android_centerX android_centerY android_endColor android_endX android_endY android_gradientRadius android_startColor android_startX android_startY android_tileMode android_type
styleable GradientColorItem android_color android_offset
styleable SplitPairFilter primaryActivityName secondaryActivityAction secondaryActivityName
styleable SplitPairRule clearTop finishPrimaryWithSecondary finishSecondaryWithPrimary splitLayoutDirection splitMinSmallestWidth splitMinWidth splitRatio
styleable SplitPlaceholderRule placeholderActivityName splitLayoutDirection splitMinSmallestWidth splitMinWidth splitRatio
xml fluwx_file_provider_paths
-- Merging decision tree log ---
manifest
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
package
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:2:5-31
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
xmlns:android
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:11-69
uses-permission#android.permission.INTERNET
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:5-67
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:22-64
uses-permission#android.permission.ACCESS_NETWORK_STATE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:5-79
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:22-76
uses-permission#android.permission.ACCESS_WIFI_STATE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:5-76
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:22-73
uses-permission#android.permission.WRITE_EXTERNAL_STORAGE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:5-81
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:22-78
queries
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:10:5-12:15
package#com.tencent.mm
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:9-50
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:18-47
application
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:14:5-60:19
activity#com.jarvan.fluwx.wxapi.FluwxWXEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:15:9-20:58
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:17:13-44
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:18:13-37
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:20:13-55
android:taskAffinity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:19:13-52
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:16:13-55
activity-alias#${applicationId}.wxapi.WXEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:22:9-35:26
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:25:13-43
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:24:13-36
android:targetActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:26:13-81
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:28:13-55
android:taskAffinity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:27:13-52
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:23:13-66
intent-filter#action:name:android.intent.action.VIEW+category:name:android.intent.category.DEFAULT+data:scheme:sdksample
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
action#android.intent.action.VIEW
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
category#android.intent.category.DEFAULT
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
data
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
android:scheme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
activity-alias#${applicationId}.wxapi.WXPayEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:36:9-49:26
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:39:13-48
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:38:13-36
android:targetActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:40:13-81
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:41:13-55
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:37:13-69
provider#com.jarvan.fluwx.FluwxFileProvider
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:51:9-59:20
android:grantUriPermissions
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:55:13-47
android:authorities
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:53:13-65
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:54:13-37
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:52:13-62
meta-data#android.support.FILE_PROVIDER_PATHS
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:56:13-58:69
android:resource
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:58:17-66
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:57:17-67
uses-sdk
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml reason: use-sdk injection requested
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
android:targetSdkVersion
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
android:minSdkVersion
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
-- Merging decision tree log ---
manifest
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:1-61:12
package
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:2:5-31
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
xmlns:android
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:1:11-69
uses-permission#android.permission.INTERNET
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:5-67
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:4:22-64
uses-permission#android.permission.ACCESS_NETWORK_STATE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:5-79
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:5:22-76
uses-permission#android.permission.ACCESS_WIFI_STATE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:5-76
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:6:22-73
uses-permission#android.permission.WRITE_EXTERNAL_STORAGE
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:5-81
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:7:22-78
queries
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:10:5-12:15
package#com.tencent.mm
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:9-50
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:11:18-47
application
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:14:5-60:19
activity#com.jarvan.fluwx.wxapi.FluwxWXEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:15:9-20:58
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:17:13-44
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:18:13-37
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:20:13-55
android:taskAffinity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:19:13-52
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:16:13-55
activity-alias#${applicationId}.wxapi.WXEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:22:9-35:26
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:25:13-43
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:24:13-36
android:targetActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:26:13-81
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:28:13-55
android:taskAffinity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:27:13-52
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:23:13-66
intent-filter#action:name:android.intent.action.VIEW+category:name:android.intent.category.DEFAULT+data:scheme:sdksample
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:30:13-34:29
action#android.intent.action.VIEW
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:17-69
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:31:25-66
category#android.intent.category.DEFAULT
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:17-76
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:32:27-73
data
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:17-52
android:scheme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:33:23-49
activity-alias#${applicationId}.wxapi.WXPayEntryActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:36:9-49:26
android:launchMode
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:39:13-48
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:38:13-36
android:targetActivity
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:40:13-81
android:theme
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:41:13-55
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:37:13-69
provider#com.jarvan.fluwx.FluwxFileProvider
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:51:9-59:20
android:grantUriPermissions
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:55:13-47
android:authorities
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:53:13-65
android:exported
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:54:13-37
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:52:13-62
meta-data#android.support.FILE_PROVIDER_PATHS
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:56:13-58:69
android:resource
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:58:17-66
android:name
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml:57:17-67
uses-sdk
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml reason: use-sdk injection requested
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
android:targetSdkVersion
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
android:minSdkVersion
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
ADDED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
INJECTED from /Users/zhangguoqing/work/code/vip/clx_flutter/fluwx_no_pay-3.9.0/android/src/main/AndroidManifest.xml
# 微信
-keep class com.tencent.mm.opensdk.** {*;}
-keep class com.tencent.wxop.** {*;}
-keep class com.tencent.mm.sdk.** {*;}
## Kotlin
# ServiceLoader support
-keepnames class kotlinx.coroutines.internal.MainDispatcherFactory {}
-keepnames class kotlinx.coroutines.CoroutineExceptionHandler {}
-keepnames class kotlinx.coroutines.android.AndroidExceptionPreHandler {}
-keepnames class kotlinx.coroutines.android.AndroidDispatcherFactory {}
# Most of volatile fields are updated with AFU and should not be mangled
-keepclassmembernames class kotlinx.** {
volatile <fields>;
}
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
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-6.7-bin.zip
rootProject.name = 'fluwx'
<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.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Support WeChat query on Android P -->
<queries>
<package android:name="com.tencent.mm" />
</queries>
<application>
<activity
android:name=".wxapi.FluwxWXEntryActivity"
android:launchMode="singleTask"
android:exported="false"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme" />
<activity-alias
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:taskAffinity="${applicationId}"
android:theme="@style/DisablePreviewTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<activity-alias
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
<provider
android:name="com.jarvan.fluwx.FluwxFileProvider"
android:authorities="${applicationId}.fluwxprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/fluwx_file_provider_paths" />
</provider>
</application>
</manifest>
package com.jarvan.fluwx
import androidx.core.content.FileProvider
/***
* Created by mo on 2020/5/13
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class FluwxFileProvider: FileProvider()
\ No newline at end of file
package com.jarvan.fluwx
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.annotation.NonNull
import com.jarvan.fluwx.handlers.*
import com.jarvan.fluwx.utils.WXApiUtils
import com.tencent.mm.opensdk.modelbiz.*
import com.tencent.mm.opensdk.modelpay.PayReq
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry
/** FluwxPlugin */
class FluwxPlugin : FlutterPlugin, MethodCallHandler, ActivityAware,
PluginRegistry.NewIntentListener {
companion object {
var callingChannel: MethodChannel? = null
// 主动获取的启动参数
var extMsg: String? = null
}
private var shareHandler: FluwxShareHandler? = null
private var authHandler: FluwxAuthHandler? = null
private var fluwxChannel: MethodChannel? = null
private var context: Context? = null
private fun handelIntent(intent: Intent) {
val action = intent.action
val dataString = intent.dataString
if (Intent.ACTION_VIEW == action) {
extMsg = dataString
}
}
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
val channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.jarvanmo/fluwx")
channel.setMethodCallHandler(this)
fluwxChannel = channel
context = flutterPluginBinding.applicationContext
authHandler = FluwxAuthHandler(channel)
shareHandler = FluwxShareHandlerEmbedding(
flutterPluginBinding.flutterAssets,
flutterPluginBinding.applicationContext
)
}
override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
callingChannel = fluwxChannel
when {
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 == "authByQRCode" -> authHandler?.authByQRCode(call, result)
call.method == "stopAuthByQRCode" -> authHandler?.stopAuthByQRCode(result)
call.method == "payWithFluwx" -> pay(call, result)
call.method == "payWithHongKongWallet" -> payWithHongKongWallet(call, result)
call.method == "launchMiniProgram" -> launchMiniProgram(call, result)
call.method == "subscribeMsg" -> subScribeMsg(call, result)
call.method == "autoDeduct" -> signAutoDeduct(call, result)
call.method == "autoDeductV2" -> autoDeductV2(call, result)
call.method == "openWXApp" -> openWXApp(result)
call.method.startsWith("share") -> shareHandler?.share(call, result)
call.method == "isWeChatInstalled" -> WXAPiHandler.checkWeChatInstallation(result)
call.method == "getExtMsg" -> getExtMsg(result)
call.method == "openWeChatCustomerServiceChat" -> openWeChatCustomerServiceChat(
call,
result
)
call.method == "checkSupportOpenBusinessView" -> WXAPiHandler.checkSupportOpenBusinessView(
result
)
call.method == "openBusinessView" -> openBusinessView(call, result)
call.method == "openWeChatInvoice" -> openWeChatInvoice(call, result);
else -> result.notImplemented()
}
}
private fun openWeChatInvoice(call: MethodCall, result: Result) {
if (WXAPiHandler.wxApi == null) {
result.error("Unassigned WxApi", "please config wxapi first", null)
return
} else {
//android 只有ChooseCard, IOS直接有ChooseInvoice
val request = ChooseCardFromWXCardPackage.Req()
request.cardType = call.argument("cardType")
request.appId = call.argument("appId")
request.locationId = call.argument("locationId")
request.cardId = call.argument("cardId")
request.canMultiSelect = call.argument("canMultiSelect")
request.timeStamp = System.currentTimeMillis().toString()
request.nonceStr = System.currentTimeMillis().toString()
request.signType = "SHA1"
request.cardSign = WXApiUtils.createSign(request.appId, request.nonceStr, request.timeStamp, request.cardType)
val done = WXAPiHandler.wxApi?.sendReq(request)
result.success(done)
}
}
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
shareHandler?.onDestroy()
authHandler?.removeAllListeners()
}
override fun onDetachedFromActivity() {
shareHandler?.permissionHandler = null
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
shareHandler?.permissionHandler = PermissionHandler(binding.activity)
handelIntent(binding.activity.intent)
}
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
// WXAPiHandler.setContext(binding.activity.applicationContext)
handelIntent(binding.activity.intent)
shareHandler?.permissionHandler = PermissionHandler(binding.activity)
}
override fun onDetachedFromActivityForConfigChanges() {
}
private fun getExtMsg(result: Result) {
result.success(extMsg)
extMsg = null
}
private fun pay(call: MethodCall, result: Result) {
if (WXAPiHandler.wxApi == null) {
result.error("Unassigned WxApi", "please config wxapi first", null)
return
} else {
// 将该app注册到微信
val request = PayReq()
request.appId = call.argument("appId")
request.partnerId = call.argument("partnerId")
request.prepayId = call.argument("prepayId")
request.packageValue = call.argument("packageValue")
request.nonceStr = call.argument("nonceStr")
request.timeStamp = call.argument<Long>("timeStamp").toString()
request.sign = call.argument("sign")
request.signType = call.argument("signType")
request.extData = call.argument("extData")
val done = WXAPiHandler.wxApi?.sendReq(request)
result.success(done)
}
}
private fun payWithHongKongWallet(call: MethodCall, result: Result) {
val prepayId = call.argument<String>("prepayId") ?: ""
val request = WXOpenBusinessWebview.Req()
request.businessType = 1
request.queryInfo = hashMapOf(
"token" to prepayId
)
result.success(WXAPiHandler.wxApi?.sendReq(request))
}
private fun openWeChatCustomerServiceChat(call: MethodCall, result: Result) {
val url = call.argument<String>("url") ?: ""
val corpId = call.argument<String>("corpId") ?: ""
val request = WXOpenCustomerServiceChat.Req()
request.corpId = corpId // 企业ID
request.url = url
result.success(WXAPiHandler.wxApi?.sendReq(request))
}
private fun openBusinessView(call: MethodCall, result: Result) {
val request = WXOpenBusinessView.Req()
request.businessType = call.argument<String>("businessType") ?: ""
request.query = call.argument<String>("query") ?: ""
request.extInfo = "{\"miniProgramType\": 0}"
result.success(WXAPiHandler.wxApi?.sendReq(request))
}
private fun signAutoDeduct(call: MethodCall, result: Result) {
val appId: String = call.argument<String>("appid") ?: ""
val mchId = call.argument<String>("mch_id") ?: ""
val planId = call.argument<String>("plan_id") ?: ""
val contractCode = call.argument<String>("contract_code") ?: ""
val requestSerial = call.argument<String>("request_serial") ?: ""
val contractDisplayAccount = call.argument<String>("contract_display_account") ?: ""
val notifyUrl = call.argument<String>("notify_url") ?: ""
val version = call.argument<String>("version") ?: ""
val sign = call.argument<String>("sign") ?: ""
val timestamp = call.argument<String>("timestamp") ?: ""
val returnApp = call.argument<String>("return_app") ?: ""
val businessType = call.argument<Int>("businessType") ?: 12
val req = WXOpenBusinessWebview.Req()
req.businessType = businessType
req.queryInfo = hashMapOf(
"appid" to appId,
"mch_id" to mchId,
"plan_id" to planId,
"contract_code" to contractCode,
"request_serial" to requestSerial,
"contract_display_account" to contractDisplayAccount,
"notify_url" to notifyUrl,
"version" to version,
"sign" to sign,
"timestamp" to timestamp,
"return_app" to returnApp
)
result.success(WXAPiHandler.wxApi?.sendReq(req))
}
private fun autoDeductV2(call: MethodCall, result: Result) {
val businessType = call.argument<Int>("businessType") ?: 12
val req = WXOpenBusinessWebview.Req()
req.businessType = businessType
req.queryInfo = call.argument<HashMap<String, String>>("queryInfo") ?: hashMapOf()
result.success(WXAPiHandler.wxApi?.sendReq(req))
}
private fun subScribeMsg(call: MethodCall, result: Result) {
val appId = call.argument<String>("appId")
val scene = call.argument<Int>("scene")
val templateId = call.argument<String>("templateId")
val reserved = call.argument<String>("reserved")
val req = SubscribeMessage.Req()
req.openId = appId
req.scene = scene!!
req.reserved = reserved
req.templateID = templateId
val b = WXAPiHandler.wxApi?.sendReq(req)
result.success(b)
}
private fun launchMiniProgram(call: MethodCall, result: Result) {
val req = WXLaunchMiniProgram.Req()
req.userName = call.argument("userName") // 填小程序原始id
req.path = call.argument<String?>("path") ?: "" //拉起小程序页面的可带参路径,不填默认拉起小程序首页
val type = call.argument("miniProgramType") ?: 0
req.miniprogramType = when (type) {
1 -> WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_TEST
2 -> WXLaunchMiniProgram.Req.MINIPROGRAM_TYPE_PREVIEW
else -> WXLaunchMiniProgram.Req.MINIPTOGRAM_TYPE_RELEASE
}// 可选打开 开发版,体验版和正式版
val done = WXAPiHandler.wxApi?.sendReq(req)
result.success(done)
}
private fun openWXApp(result: Result) = result.success(WXAPiHandler.wxApi?.openWXApp())
override fun onNewIntent(intent: Intent): Boolean {
handelIntent(intent)
return false
}
}
\ No newline at end of file
/*
* Copyright (C) 2020 The OpenFlutter Organization
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.handlers
import com.tencent.mm.opensdk.diffdev.DiffDevOAuthFactory
import com.tencent.mm.opensdk.diffdev.OAuthErrCode
import com.tencent.mm.opensdk.diffdev.OAuthListener
import com.tencent.mm.opensdk.modelmsg.SendAuth
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
internal class FluwxAuthHandler(private val methodChannel: MethodChannel) {
// private DiffDevOAuthFactory.getDiffDevOAuth()
private val qrCodeAuth by lazy {
DiffDevOAuthFactory.getDiffDevOAuth()
}
private val qrCodeAuthListener by lazy {
object : OAuthListener {
override fun onAuthFinish(p0: OAuthErrCode, authCode: String?) {
methodChannel.invokeMethod("onAuthByQRCodeFinished", mapOf(
"errCode" to p0.code,
"authCode" to authCode
))
}
override fun onAuthGotQrcode(p0: String?, p1: ByteArray) {
methodChannel.invokeMethod("onAuthGotQRCode", mapOf("errCode" to 0, "qrCode" to p1))
}
override fun onQrcodeScanned() {
methodChannel.invokeMethod("onQRCodeScanned", mapOf("errCode" to 0))
}
}
}
fun sendAuth(call: MethodCall, result: MethodChannel.Result) {
val req = SendAuth.Req()
req.scope = call.argument("scope")
req.state = call.argument("state")
val openId = call.argument<String?>("openId")
if (!openId.isNullOrBlank()) {
req.openId = call.argument("openId")
}
result.success(WXAPiHandler.wxApi?.sendReq(req))
}
fun authByQRCode(call: MethodCall, result: MethodChannel.Result) {
val appId = call.argument("appId") ?: ""
val scope = call.argument("scope") ?: ""
val nonceStr = call.argument("nonceStr") ?: ""
val timeStamp = call.argument("timeStamp") ?: ""
val signature = call.argument("signature") ?: ""
// val schemeData = call.argument("schemeData")?:""
result.success(qrCodeAuth.auth(appId, scope, nonceStr, timeStamp, signature, qrCodeAuthListener))
}
fun stopAuthByQRCode(result: MethodChannel.Result) {
result.success(qrCodeAuth.stopAuth())
}
fun removeAllListeners() {
qrCodeAuth.removeAllListeners()
}
}
\ No newline at end of file
/*
* Copyright (C) 2020 The OpenFlutter Organization
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.handlers
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.core.content.ContextCompat.startActivity
import com.jarvan.fluwx.FluwxPlugin
import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelmsg.ShowMessageFromWX
import java.security.cert.Extension
object FluwxRequestHandler {
private const val KEY_FLUWX_REQUEST_INFO_BUNDLE = "KEY_FLUWX_REQUEST_INFO_BUNDLE"
var customOnReqDelegate: ((baseReq: BaseReq, activity: Activity) -> Unit)? = null
fun handleRequestInfoFromIntent(intent: Intent) {
intent.getBundleExtra(KEY_FLUWX_REQUEST_INFO_BUNDLE)?.run {
val type = getInt("_wxapi_command_type", -9999)
if (type == 4) {
handleShowMessageFromWXBundle(this)
}
}
}
private fun handleShowMessageFromWXBundle(bundle: Bundle) = handleWXShowMessageFromWX(ShowMessageFromWX.Req(bundle))
private fun handleRequest(req: BaseReq) {
when (req) {
is ShowMessageFromWX.Req -> handleWXShowMessageFromWX(req)
}
}
private fun handleWXShowMessageFromWX(req: ShowMessageFromWX.Req) {
val result = mapOf(
"extMsg" to req.message.messageExt
)
FluwxPlugin.extMsg = req.message.messageExt;
FluwxPlugin.callingChannel?.invokeMethod("onWXShowMessageFromWX", result)
}
private fun defaultOnReqDelegate(baseReq: BaseReq, activity: Activity) {
// FIXME: 可能是官方的Bug,从微信拉起APP的Intent类型不对,无法跳转回Flutter Activity
// 稳定复现场景:微信版本为7.0.5,小程序SDK为2.7.7
if (baseReq.type == 4) {
// com.tencent.mm.opensdk.constants.ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX = 4
if (!WXAPiHandler.coolBoot) {
handleRequest(baseReq)
startSpecifiedActivity(defaultFlutterActivityAction(activity), activity = activity)
} else {
when (baseReq) {
is ShowMessageFromWX.Req -> {
try {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("wechatextmsg://${activity.packageName}/?extmsg=${baseReq.message.messageExt}"))
activity.startActivity(intent)
activity.finish()
WXAPiHandler.coolBoot = false
}catch (e:Exception) {
Log.i("fluwx","call scheme error:${e.toString()}")
}
}
}
}
}
}
fun onReq(baseReq: BaseReq, activity: Activity) {
try {
val packageManager = activity.packageManager
val appInfo = packageManager.getApplicationInfo(activity.packageName, PackageManager.GET_META_DATA)
val defaultHandle = appInfo.metaData.getBoolean("handleWeChatRequestByFluwx", true)
if (defaultHandle) {
defaultOnReqDelegate(baseReq, activity)
} else {
customOnReqDelegate?.invoke(baseReq, activity)
}
} catch (e: Exception) {
Log.i("Fluwx", "can't load meta-data handleWeChatRequestByFluwx")
}
}
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
/*
* Copyright (C) 2020 The OpenFlutter Organization
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.handlers
import com.jarvan.fluwx.FluwxPlugin
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.modelbiz.*
import com.tencent.mm.opensdk.modelmsg.SendAuth
import com.tencent.mm.opensdk.modelmsg.SendMessageToWX
import com.tencent.mm.opensdk.modelpay.PayResp
import io.flutter.plugin.common.MethodChannel
object FluwxResponseHandler {
private const val errStr = "errStr"
private const val errCode = "errCode"
private const val openId = "openId"
private const val type = "type"
fun handleResponse(response: BaseResp) {
when (response) {
is SendAuth.Resp -> handleAuthResponse(response)
is SendMessageToWX.Resp -> handleSendMessageResp(response)
is PayResp -> handlePayResp(response)
is WXLaunchMiniProgram.Resp -> handleLaunchMiniProgramResponse(response)
is SubscribeMessage.Resp -> handleSubscribeMessage(response)
is WXOpenBusinessWebview.Resp -> handlerWXOpenBusinessWebviewResponse(response)
is WXOpenCustomerServiceChat.Resp -> handlerWXOpenCustomerServiceChatResponse(response)
is WXOpenBusinessView.Resp -> handleWXOpenBusinessView(response)
is ChooseCardFromWXCardPackage.Resp -> handleWXOpenInvoiceResponse(response)
}
}
private fun handleWXOpenInvoiceResponse(response: ChooseCardFromWXCardPackage.Resp) {
val result = mapOf(
"cardItemList" to response.cardItemList,
"transaction" to response.transaction,
"openid" to response.openId,
errStr to response.errStr,
type to response.type,
errCode to response.errCode)
FluwxPlugin.callingChannel?.invokeMethod("onOpenWechatInvoiceResponse", result)
}
private fun handleWXOpenBusinessView(response: WXOpenBusinessView.Resp) {
val result = mapOf(
"openid" to response.openId,
"extMsg" to response.extMsg,
"businessType" to response.businessType,
errStr to response.errStr,
type to response.type,
errCode to response.errCode)
FluwxPlugin.callingChannel?.invokeMethod("onOpenBusinessViewResponse", result)
}
private fun handleSubscribeMessage(response: SubscribeMessage.Resp) {
val result = mapOf(
"openid" to response.openId,
"templateId" to response.templateID,
"action" to response.action,
"reserved" to response.reserved,
"scene" to response.scene,
type to response.type)
FluwxPlugin.callingChannel?.invokeMethod("onSubscribeMsgResp", result)
}
private fun handleLaunchMiniProgramResponse(response: WXLaunchMiniProgram.Resp) {
val result = mutableMapOf(
errStr to response.errStr,
type to response.type,
errCode to response.errCode,
openId to response.openId
)
response.extMsg?.let {
result["extMsg"] = response.extMsg
}
FluwxPlugin.callingChannel?.invokeMethod("onLaunchMiniProgramResponse", result)
}
private fun handlePayResp(response: PayResp) {
val result = mapOf(
"prepayId" to response.prepayId,
"returnKey" to response.returnKey,
"extData" to response.extData,
errStr to response.errStr,
type to response.type,
errCode to response.errCode
)
FluwxPlugin.callingChannel?.invokeMethod("onPayResponse", result)
}
private fun handleSendMessageResp(response: SendMessageToWX.Resp) {
val result = mapOf(
errStr to response.errStr,
type to response.type,
errCode to response.errCode,
openId to response.openId)
FluwxPlugin.callingChannel?.invokeMethod("onShareResponse", result)
}
private fun handleAuthResponse(response: SendAuth.Resp) {
val result = mapOf(
errCode to response.errCode,
"code" to response.code,
"state" to response.state,
"lang" to response.lang,
"country" to response.country,
errStr to response.errStr,
openId to response.openId,
"url" to response.url,
type to response.type)
FluwxPlugin.callingChannel?.invokeMethod("onAuthResponse", result)
}
private fun handlerWXOpenBusinessWebviewResponse(response: WXOpenBusinessWebview.Resp) {
val result = mapOf(
errCode to response.errCode,
"businessType" to response.businessType,
"resultInfo" to response.resultInfo,
errStr to response.errStr,
openId to response.openId,
type to response.type)
FluwxPlugin.callingChannel?.invokeMethod("onWXOpenBusinessWebviewResponse", result)
}
private fun handlerWXOpenCustomerServiceChatResponse(response: WXOpenCustomerServiceChat.Resp) {
val result = mapOf(
errCode to response.errCode,
errStr to response.errStr,
openId to response.openId,
type to response.type)
FluwxPlugin.callingChannel?.invokeMethod("onWXOpenCustomerServiceChatResponse", result)
}
}
\ No newline at end of file
package com.jarvan.fluwx.handlers
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.AssetFileDescriptor
import android.net.Uri
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import com.jarvan.fluwx.io.*
import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelmsg.*
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import kotlinx.coroutines.*
import java.io.File
import java.util.*
import kotlin.coroutines.CoroutineContext
/***
* Created by mo on 2020/3/6
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
internal class FluwxShareHandlerEmbedding(private val flutterAssets: FlutterPlugin.FlutterAssets, override val context: Context) : FluwxShareHandler {
override val assetFileDescriptor: (String) -> AssetFileDescriptor = {
val uri = Uri.parse(it)
val packageName = uri.getQueryParameter("package")
val subPath = if (packageName.isNullOrBlank()) {
flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty())
} else {
flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty(), packageName)
}
context.assets.openFd(subPath)
}
override val job: Job = Job()
override var permissionHandler: PermissionHandler? = null
}
internal interface FluwxShareHandler : CoroutineScope {
companion object {
const val SHARE_IMAGE_THUMB_LENGTH = 32 * 1024
const val SHARE_MINI_PROGRAM_THUMB_LENGTH = 120 * 1024
private const val keyTitle = "title"
private const val keyThumbnail = "thumbnail"
private const val keyDescription = "description"
}
fun share(call: MethodCall, result: MethodChannel.Result) {
if (WXAPiHandler.wxApi == null) {
result.error("Unassigned WxApi", "please config wxapi first", null)
return
}
when (call.method) {
"shareText" -> shareText(call, result)
"shareMiniProgram" -> shareMiniProgram(call, result)
"shareImage" -> shareImage(call, result)
"shareMusic" -> shareMusic(call, result)
"shareVideo" -> shareVideo(call, result)
"shareWebPage" -> shareWebPage(call, result)
"shareFile" -> shareFile(call, result)
else -> {
result.notImplemented()
}
}
}
private fun shareText(call: MethodCall, result: MethodChannel.Result) {
val textObj = WXTextObject(call.argument("source"))
val msg = WXMediaMessage()
msg.mediaObject = textObj
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
result.success(WXAPiHandler.wxApi?.sendReq(req))
}
private fun shareMiniProgram(call: MethodCall, result: MethodChannel.Result) {
val miniProgramObj = WXMiniProgramObject()
miniProgramObj.webpageUrl = call.argument("webPageUrl") // 兼容低版本的网页链接
miniProgramObj.miniprogramType = call.argument("miniProgramType") ?: 0// 正式版:0,测试版:1,体验版:2
miniProgramObj.userName = call.argument("userName") // 小程序原始id
miniProgramObj.path = call.argument("path") //小程序页面路径
miniProgramObj.withShareTicket = call.argument("withShareTicket") ?: true
val msg = WXMediaMessage(miniProgramObj)
msg.title = call.argument(keyTitle) // 小程序消息title
msg.description = call.argument(keyDescription) // 小程序消息desc
launch {
msg.thumbData = readThumbnailByteArray(call, length = SHARE_MINI_PROGRAM_THUMB_LENGTH)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private fun shareImage(call: MethodCall, result: MethodChannel.Result) {
launch {
val map: Map<String, Any> = call.argument("source") ?: mapOf()
val sourceImage = WeChatFile.createWeChatFile(map, assetFileDescriptor)
val thumbData = readThumbnailByteArray(call)
val sourceByteArray = sourceImage.readByteArray()
val imageObject = when {
sourceByteArray.isEmpty() -> {
WXImageObject()
}
else -> {
WXImageObject().apply {
if (supportFileProvider && targetHigherThanN) {
setImagePath(getFileContentUri(sourceByteArray.toCacheFile(context, sourceImage.suffix)))
} else {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
setImagePath(sourceByteArray.toExternalCacheFile(context, sourceImage.suffix)?.absolutePath)
} else {
permissionHandler?.requestStoragePermission()
}
}
}
}
}
val msg = WXMediaMessage()
msg.mediaObject = imageObject
msg.thumbData = thumbData
msg.description = call.argument(keyDescription)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private fun shareMusic(call: MethodCall, result: MethodChannel.Result) {
val music = WXMusicObject()
val musicUrl: String? = call.argument("musicUrl")
val musicLowBandUrl: String? = call.argument("musicLowBandUrl")
if (musicUrl != null && musicUrl.isNotBlank()) {
music.musicUrl = musicUrl
music.musicDataUrl = call.argument("musicDataUrl")
} else {
music.musicLowBandUrl = musicLowBandUrl
music.musicLowBandDataUrl = call.argument("musicLowBandDataUrl")
}
val msg = WXMediaMessage()
msg.mediaObject = music
msg.description = call.argument(keyDescription)
launch {
msg.thumbData = readThumbnailByteArray(call)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private fun shareVideo(call: MethodCall, result: MethodChannel.Result) {
val video = WXVideoObject()
val videoUrl: String? = call.argument("videoUrl")
val videoLowBandUrl: String? = call.argument("videoLowBandUrl")
if (videoUrl != null && videoUrl.isNotBlank()) {
video.videoUrl = videoUrl
} else {
video.videoLowBandUrl = videoLowBandUrl
}
val msg = WXMediaMessage()
msg.mediaObject = video
msg.description = call.argument(keyDescription)
launch {
msg.thumbData = readThumbnailByteArray(call)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private fun shareWebPage(call: MethodCall, result: MethodChannel.Result) {
val webPage = WXWebpageObject()
webPage.webpageUrl = call.argument("webPage")
val msg = WXMediaMessage()
msg.mediaObject = webPage
msg.description = call.argument(keyDescription)
launch {
msg.thumbData = readThumbnailByteArray(call)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private fun shareFile(call: MethodCall, result: MethodChannel.Result) {
launch {
val wxFileObject = WXFileObject()
// val filePath: String? = call.argument("filePath")
// wxFileObject.filePath = filePath
val msg = WXMediaMessage()
msg.mediaObject = wxFileObject
msg.description = call.argument("description")
val map: Map<String, Any> = call.argument("source") ?: mapOf()
val sourceFile = WeChatFile.createWeChatFile(map, assetFileDescriptor)
val sourceByteArray = sourceFile.readByteArray()
wxFileObject.apply {
if (supportFileProvider && targetHigherThanN) {
setFilePath(getFileContentUri(sourceByteArray.toCacheFile(context, sourceFile.suffix)))
} else {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
filePath = sourceByteArray.toExternalCacheFile(context, sourceFile.suffix)?.absolutePath
} else {
permissionHandler?.requestStoragePermission()
}
}
}
msg.thumbData = readThumbnailByteArray(call)
val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg)
req.message = msg
sendRequestInMain(result, req)
}
}
private suspend fun sendRequestInMain(result: MethodChannel.Result, request: BaseReq) = withContext(Dispatchers.Main) {
result.success(WXAPiHandler.wxApi?.sendReq(request))
}
private suspend fun readThumbnailByteArray(call: MethodCall, length: Int = SHARE_IMAGE_THUMB_LENGTH): ByteArray? {
val thumbnailMap: Map<String, Any>? = call.argument(keyThumbnail)
val compress:Boolean = call.argument("compressThumbnail")?:true
return thumbnailMap?.run {
val thumbnailImage = WeChatFile.createWeChatFile(thumbnailMap, assetFileDescriptor)
val thumbnailImageIO = ImagesIOIml(thumbnailImage)
if(compress){
compressThumbnail(thumbnailImageIO, length)
}else{
thumbnailImageIO.readByteArray()
}
}
}
private suspend fun compressThumbnail(ioIml: ImagesIO, length: Int) = ioIml.compressedByteArray(context, length)
// SESSION, TIMELINE, FAVORITE
private fun setCommonArguments(call: MethodCall, req: SendMessageToWX.Req, msg: WXMediaMessage) {
msg.messageAction = call.argument("messageAction")
msg.messageExt = call.argument("messageExt")
msg.mediaTagName = call.argument("mediaTagName")
msg.title = call.argument(keyTitle)
msg.description = call.argument(keyDescription)
req.transaction = UUID.randomUUID().toString().replace("-", "")
val sceneIndex = call.argument<Int?>("scene")
req.scene = when (sceneIndex) {
0 -> SendMessageToWX.Req.WXSceneSession
1 -> SendMessageToWX.Req.WXSceneTimeline
2 -> SendMessageToWX.Req.WXSceneFavorite
else -> SendMessageToWX.Req.WXSceneSession
}
}
private fun getFileContentUri(file: File?): String? {
if (file == null || !file.exists())
return null
val contentUri = FileProvider.getUriForFile(context,
"${context.packageName}.fluwxprovider", // 要与`AndroidManifest.xml`里配置的`authorities`一致,假设你的应用包名为com.example.app
file)
// 授权给微信访问路径
context.grantUriPermission("com.tencent.mm", // 这里填微信包名
contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
return contentUri.toString() // contentUri.toString() 即是以"content://"开头的用于共享的路径
}
private val supportFileProvider: Boolean get() = WXAPiHandler.wxApi?.wxAppSupportAPI ?: 0 >= 0x27000D00
private val targetHigherThanN: Boolean get() = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N
val context: Context
val assetFileDescriptor: (String) -> AssetFileDescriptor
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
val job: Job
var permissionHandler: PermissionHandler?
fun onDestroy() = job.cancel()
}
package com.jarvan.fluwx.handlers
import android.Manifest
import android.app.Activity
import android.app.Fragment
import android.os.Build
/***
* Created by mo on 2020/3/27
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class PermissionHandler(private val activity: Activity?) {
private val tag = "Fragment_TAG"
private val fragment: Fragment = Fragment()
fun requestStoragePermission() {
if (oldFragment != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
oldFragment?.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 12121)
}
} else {
activity?.run {
val ft = fragmentManager.beginTransaction()
ft.add(fragment, tag)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ft.commitNow()
} else {
ft.commit()
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
fragment.requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 12121)
}
}
}
}
private val oldFragment get() = activity?.fragmentManager?.findFragmentByTag(tag)
}
\ No newline at end of file
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.jarvan.fluwx.handlers
import android.content.Context
import android.util.Log
import com.tencent.mm.opensdk.constants.Build
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import com.tencent.mm.opensdk.utils.ILog
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
object WXAPiHandler : ILog {
var wxApi: IWXAPI? = null
// private var context: Context? = null
private var registered: Boolean = false
val wxApiRegistered get() = registered
//是否为冷启动
var coolBoot: Boolean = false
fun setupWxApi(appId: String, context: Context, force: Boolean = true): Boolean {
if (force || !registered) {
// setContext(context)
registerWxAPIInternal(appId, context)
}
return registered
}
//
// fun setContext(context: Context?) {
// WXAPiHandler.context = context
// }
fun registerApp(call: MethodCall, result: MethodChannel.Result, context: Context?) {
if (call.argument<Boolean?>("android") == false) {
return
}
if (wxApi != null) {
result.success(true)
return
}
val appId: String? = call.argument("appId")
if (appId.isNullOrBlank()) {
result.error("invalid app id", "are you sure your app id is correct ?", appId)
return
}
context?.let {
registerWxAPIInternal(appId, it)
}
result.success(registered)
}
fun checkWeChatInstallation(result: MethodChannel.Result) {
if (wxApi == null) {
result.error("Unassigned WxApi", "please config wxapi first", null)
return
} else {
result.success(wxApi?.isWXAppInstalled)
}
}
fun checkSupportOpenBusinessView(result: MethodChannel.Result) {
when {
wxApi == null -> {
result.error("Unassigned WxApi", "please config wxapi first", null)
}
wxApi?.isWXAppInstalled != true -> {
result.error("WeChat Not Installed", "Please install the WeChat first", null)
}
wxApi?.wxAppSupportAPI ?: 0 < Build.OPEN_BUSINESS_VIEW_SDK_INT -> {
result.error("WeChat Not Supported", "Please upgrade the WeChat version", null)
}
else -> {
result.success(true)
}
}
}
private fun registerWxAPIInternal(appId: String, context: Context) {
val api = WXAPIFactory.createWXAPI(context.applicationContext, appId)
registered = api.registerApp(appId)
wxApi = api
}
fun startLog(call: MethodCall, result: MethodChannel.Result) {
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?) {
when {
p1 != null -> {
Log.d(p0, p1);
}
}
}
override fun i(p0: String?, p1: String?) {
when {
p1 != null -> {
Log.d(p0, p1);
}
}
}
override fun e(p0: String?, p1: String?) {
when {
p1 != null -> {
Log.d(p0, p1);
}
}
}
override fun v(p0: String?, p1: String?) {
when {
p1 != null -> {
Log.d(p0, p1);
}
}
}
override fun w(p0: String?, p1: String?) {
when {
p1 != null -> {
Log.d(p0, p1);
}
}
}
}
package com.jarvan.fluwx.io
import android.content.Context
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okio.*
import java.io.*
import java.io.IOException
import java.util.*
/***
* Created by mo on 2020/5/13
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
private const val cachePathName = "fluwxSharedData"
internal suspend fun ByteArray.toExternalCacheFile(context: Context, suffix: String): File? {
var file: File? = null
val externalFile = context.externalCacheDir ?: return file
val dir = File(externalFile.absolutePath + File.separator + cachePathName).apply {
if (!exists()) {
mkdirs()
}
}
file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix)
return saveToLocal(this, file)
}
internal suspend fun ByteArray.toCacheFile(context: Context, suffix: String): File? {
var file: File? = null
val externalFile = context.cacheDir ?: return file
val dir = File(externalFile.absolutePath + File.separator + cachePathName).apply {
if (!exists()) {
mkdirs()
}
}
file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix)
return saveToLocal(this, file)
}
private suspend fun saveToLocal(byteArray: ByteArray, file: File): File? {
return withContext(Dispatchers.IO) {
var sink: BufferedSink? = null
var source: Source? = null
var outputStream: OutputStream? = null
try {
outputStream = FileOutputStream(file)
sink = outputStream.sink().buffer()
source = ByteArrayInputStream(byteArray).source()
sink.writeAll(source)
sink.flush()
} catch (e: IOException) {
Log.w("Fluwx", "failed to create cache files")
} finally {
sink?.close()
source?.close()
outputStream?.close()
}
file
}
}
package com.jarvan.fluwx.io
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import id.zelory.compressor.Compressor
import id.zelory.compressor.constraint.size
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okio.*
import java.io.*
import java.io.IOException
import java.util.*
import kotlin.math.sqrt
/***
* Created by mo on 2020/3/7
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class ImagesIOIml(override val image: WeChatFile) : ImagesIO {
override suspend fun readByteArray(): ByteArray = image.readByteArray()
override suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray =
withContext(Dispatchers.IO) {
val originalByteArray = readByteArray()
if (originalByteArray.isEmpty())
return@withContext originalByteArray
val originFile = inputStreamToFile(ByteArrayInputStream(originalByteArray))
if (image.suffix.contains("gif")) {
return@withContext originalByteArray
}
val compressedFile = Compressor.compress(context, originFile) {
size(maxFileSize = maxSize * 1024L)
}
if (compressedFile.length() < maxSize) {
val source = compressedFile.source()
val bufferedSource = source.buffer()
val bytes = bufferedSource.readByteArray()
source.close()
bufferedSource.close()
bytes
} else {
createScaledBitmapWithRatio(compressedFile, maxSize)
}
}
private fun inputStreamToFile(inputStream: InputStream): File {
val file = File.createTempFile(UUID.randomUUID().toString(), image.suffix)
val outputStream: OutputStream = FileOutputStream(file)
val sink = outputStream.sink().buffer()
val source = inputStream.source()
sink.writeAll(source)
source.close()
sink.close()
return file
}
private fun createScaledBitmapWithRatio(file: File, maxSize: Int): ByteArray {
val originBitmap = BitmapFactory.decodeFile(file.absolutePath)
val result: Bitmap? = createScaledBitmapWithRatio(originBitmap, maxSize, true)
result ?: return byteArrayOf()
return bmpToByteArray(result, image.suffix) ?: byteArrayOf()
}
private fun createScaledBitmapWithRatio(
bitmap: Bitmap,
maxLength: Int,
recycle: Boolean
): Bitmap? {
var result = bitmap
while (true) {
val ratio = maxLength.toDouble() / result.byteCount
val width = result.width * sqrt(ratio)
val height = result.height * sqrt(ratio)
val tmp = Bitmap.createScaledBitmap(result, width.toInt(), height.toInt(), true)
if (result != bitmap) {
result.recycle()
}
result = tmp
if (result.byteCount < maxLength) {
break
}
}
if (recycle) {
bitmap.recycle()
}
return result
}
private fun bmpToByteArray(
bitmap: Bitmap,
suffix: String
): ByteArray? { // int bytes = bitmap.getByteCount();
val byteArrayOutputStream = ByteArrayOutputStream()
var format = CompressFormat.PNG
if (suffix.toLowerCase(Locale.US) == ".jpg" || suffix.toLowerCase(Locale.US) == ".jpeg") {
format = CompressFormat.JPEG
}
bitmap.compress(format, 100, byteArrayOutputStream)
val inputStream: InputStream = ByteArrayInputStream(byteArrayOutputStream.toByteArray())
var result: ByteArray? = null
bitmap.recycle()
val source = inputStream.source()
val bufferedSource = source.buffer()
try {
result = bufferedSource.readByteArray()
source.close()
bufferedSource.close()
} catch (e: IOException) {
e.printStackTrace()
}
return result
}
}
interface ImagesIO {
val image: WeChatFile
suspend fun readByteArray(): ByteArray
suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray
}
package com.jarvan.fluwx.io
import android.content.res.AssetFileDescriptor
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.BufferedSource
import okio.buffer
import okio.source
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
/***
* Created by mo on 2020/5/13
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class WeChatFileFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: File
init {
if (source !is File)
throw IllegalArgumentException("source should be File but it's ${source::class.java.name}")
else
internalSource = source
}
override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) {
var source: BufferedSource? = null
try {
source = internalSource.source().buffer()
val array = source.readByteArray()
array
} catch (e: FileNotFoundException) {
byteArrayOf()
} catch (io: IOException) {
byteArrayOf()
} finally {
source?.close()
}
}
}
private class WeChatAssetFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: AssetFileDescriptor
init {
if (source !is AssetFileDescriptor)
throw IllegalArgumentException("source should be AssetFileDescriptor but it's ${source::class.java.name}")
else
internalSource = source
}
override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) {
var source: BufferedSource? = null
try {
source = internalSource.createInputStream().source().buffer()
val array = source.readByteArray()
array
} catch (e: FileNotFoundException) {
byteArrayOf()
} catch (io: IOException) {
byteArrayOf()
} finally {
source?.close()
}
}
}
private class WeChatNetworkFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: String
init {
if (source !is String)
throw IllegalArgumentException("source should be String but it's ${source::class.java.name}")
else
internalSource = source
}
override suspend fun readByteArray(): ByteArray = withContext(Dispatchers.IO) {
val okHttpClient = OkHttpClient.Builder().build()
val request: Request = Request.Builder().url(internalSource).get().build()
try {
val response = okHttpClient.newCall(request).execute()
val responseBody = response.body
if (response.isSuccessful && responseBody != null) {
responseBody.bytes()
} else {
byteArrayOf()
}
} catch (e: IOException) {
Log.w("Fluwx", "reading file from $internalSource failed")
byteArrayOf()
}
}
}
private class WeChatMemoryFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: ByteArray
init {
if (source !is ByteArray)
throw IllegalArgumentException("source should be String but it's ${source::class.java.name}")
else
internalSource = source
}
override suspend fun readByteArray(): ByteArray = internalSource
}
interface WeChatFile {
val source: Any
val suffix: String
suspend fun readByteArray(): ByteArray
companion object {
// NETWORK,
// ASSET,
// FILE,
// BINARY,
fun createWeChatFile(params: Map<String, Any>, assetFileDescriptor: (String) -> AssetFileDescriptor): WeChatFile {
// Map toMap() => {"source": source, "schema": schema.index, "suffix": suffix};
val suffix = (params["suffix"] as String?) ?: ".jpeg"
return when ((params["schema"] as? Int) ?: 0) {
0 -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix)
1 -> WeChatAssetFile(source = assetFileDescriptor(((params["source"] as? String).orEmpty())), suffix = suffix)
2 -> WeChatFileFile(source = File((params["source"] as? String).orEmpty()), suffix = suffix)
3 -> WeChatMemoryFile(source = (params["source"] as? ByteArray)
?: byteArrayOf(), suffix = suffix)
else -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix)
}
}
}
}
package com.jarvan.fluwx.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
public class WXApiUtils {
public static String createSign(String appId, String nonceStr, String timestamp, String card_type) {
SortedMap<Object, Object> parameters = new TreeMap<>();
parameters.put("app_id", appId);
parameters.put("nonce_str", nonceStr);
parameters.put("card_type", timestamp);
parameters.put("time_stamp", card_type);
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
// 所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
@SuppressWarnings("rawtypes")
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k)
&& !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
String sign = shaEncode(sb.toString()).toUpperCase();
return sign;
}
public static String shaEncode(String inStr) {
MessageDigest sha = null;
try {
sha = MessageDigest.getInstance("SHA");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
byte[] byteArray = new byte[0];
try {
byteArray = inStr.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
byte[] md5Bytes = sha.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
}
/*
* Copyright (C) 2020 The OpenFlutter Organization
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.wxapi
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import com.jarvan.fluwx.handlers.FluwxResponseHandler
import com.jarvan.fluwx.handlers.FluwxRequestHandler
import com.jarvan.fluwx.handlers.WXAPiHandler
import com.tencent.mm.opensdk.modelbase.BaseReq
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
import io.flutter.Log
open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
// IWXAPI 是第三方app和微信通信的openapi接口
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
if (!WXAPiHandler.wxApiRegistered) {
val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val wechatAppId = appInfo.metaData.getString("weChatAppId")
if (wechatAppId != null) {
WXAPiHandler.setupWxApi(wechatAppId,this)
WXAPiHandler.coolBoot = true
} else {
Log.e("fluwx","can't load meta-data weChatAppId")
}
}
WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) {
e.printStackTrace()
startSpecifiedActivity(defaultFlutterActivityAction())
finish()
}
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
try {
WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) {
e.printStackTrace()
startSpecifiedActivity(defaultFlutterActivityAction())
finish()
}
}
override fun onReq(baseReq: BaseReq) {
// FIXME: 可能是官方的Bug,从微信拉起APP的Intent类型不对,无法跳转回Flutter Activity
// 稳定复现场景:微信版本为7.0.5,小程序SDK为2.7.7
FluwxRequestHandler.onReq(baseReq,this)
}
// 第三方应用发送到微信的请求处理后的响应结果,会回调到该方法
override fun onResp(resp: BaseResp) {
FluwxResponseHandler.handleResponse(resp)
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
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="DisablePreviewTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowIsTranslucent">false</item>
<item name="android:windowDisablePreview">true</item>
</style>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="fluwxSharedData" path="fluwxSharedData/"/>
</paths>
\ No newline at end of file
package com.jarvan.fluwx
class FluwxTest {
fun test(){}
}
\ No newline at end of file
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import "FluwxPlugin.h"
#import "WXApiRequestHandler.h"
#import "WechatAuthSDK.h"
@class FluwxStringUtil;
@interface FluwxAuthHandler : NSObject <WechatAuthAPIDelegate>
- (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar methodChannel:(FlutterMethodChannel *)flutterMethodChannel;
- (void)handleAuth:(FlutterMethodCall *)call result:(FlutterResult)result;
- (void)authByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result;
- (void)stopAuthByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result;
- (void)handleAuthByPhoneLogin:(FlutterMethodCall*)call result:(FlutterResult)result;
@end
//
// Created by mo on 2020/3/7.
//
#import "FluwxAuthHandler.h"
@implementation FluwxAuthHandler
WechatAuthSDK *_qrauth;
FlutterMethodChannel *_fluwxMethodChannel = nil;
- (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar methodChannel:(FlutterMethodChannel *)flutterMethodChannel {
self = [super init];
if (self) {
_qrauth = [[WechatAuthSDK alloc] init];
_qrauth.delegate = self;
_fluwxMethodChannel = flutterMethodChannel;
}
return self;
}
- (void)handleAuthByPhoneLogin:(FlutterMethodCall*)call result:(FlutterResult)result{
UIViewController *vc = UIApplication.sharedApplication.keyWindow.rootViewController;
SendAuthReq *authReq = [[SendAuthReq alloc]init];
authReq.scope = call.arguments[@"scope"];
authReq.state = (call.arguments[@"state"] == (id) [NSNull null]) ? nil : call.arguments[@"state"];
[WXApi sendAuthReq:authReq viewController:vc delegate:[FluwxResponseHandler defaultManager] completion:^(BOOL success) {
result(@(success));
}];
}
- (void)handleAuth:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *openId = call.arguments[@"openId"];
[WXApiRequestHandler sendAuthRequestScope:call.arguments[@"scope"]
State:(call.arguments[@"state"] == (id) [NSNull null]) ? nil : call.arguments[@"state"]
OpenID:(openId == (id) [NSNull null]) ? nil : openId completion:^(BOOL done) {
result(@(done));
}];
}
- (void)authByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *appId = call.arguments[@"appId"];
NSString *scope = call.arguments[@"scope"];
NSString *nonceStr = call.arguments[@"nonceStr"];
NSString *timeStamp = call.arguments[@"timeStamp"];
NSString *signature = call.arguments[@"signature"];
NSString *schemeData = (call.arguments[@"schemeData"] == (id) [NSNull null]) ? nil : call.arguments[@"schemeData"];
BOOL done = [_qrauth Auth:appId nonceStr:nonceStr timeStamp:timeStamp scope:scope signature:signature schemeData:schemeData];
result(@(done));
}
- (void)stopAuthByQRCode:(FlutterMethodCall *)call result:(FlutterResult)result {
BOOL done = [_qrauth StopAuth];
result(@(done));
}
- (void)onQrcodeScanned {
[_fluwxMethodChannel invokeMethod:@"onQRCodeScanned" arguments:@{@"errCode": @0}];
}
- (void)onAuthGotQrcode:(UIImage *)image {
NSData *imageData = UIImagePNGRepresentation(image);
// if (imageData == nil) {
// imageData = UIImageJPEGRepresentation(image, 1);
// }
[_fluwxMethodChannel invokeMethod:@"onAuthGotQRCode" arguments:@{@"errCode": @0, @"qrCode": imageData}];
}
- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode {
NSDictionary *errorCode = @{@"errCode": @(errCode)};
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:errorCode];
if (authCode != nil) {
result[@"authCode"] = authCode;
}
[_fluwxMethodChannel invokeMethod:@"onAuthByQRCodeFinished" arguments:result];
}
@end
//
// FluwxDelegate.m
// fluwx
//
// Created by Mo on 2022/3/6.
//
#import <Foundation/Foundation.h>
#import "FluwxDelegate.h"
#import "WXApi.h"
@implementation FluwxDelegate
+ (instancetype)defaultManager {
static dispatch_once_t onceToken;
static FluwxDelegate *instance;
dispatch_once(&onceToken, ^{
instance = [[FluwxDelegate alloc] init];
});
return instance;
}
- (void) registerWxAPI:(NSString *)appId universalLink:(NSString *)universalLink {
[WXApi registerApp:appId universalLink:universalLink];
}
@end
#import "FluwxPlugin.h"
#import "FluwxResponseHandler.h"
#import "FluwxStringUtil.h"
#import "FluwxAuthHandler.h"
#import "FluwxShareHandler.h"
#import "FluwxDelegate.h"
@interface FluwxPlugin()<WXApiManagerDelegate>
@property (strong,nonatomic)NSString *extMsg;
@end
typedef void(^FluwxWXReqRunnable)(void);
@implementation FluwxPlugin
FluwxAuthHandler *_fluwxAuthHandler;
FluwxShareHandler *_fluwxShareHandler;
BOOL _isRunning;
FluwxWXReqRunnable _initialWXReqRunnable;
BOOL handleOpenURLByFluwx = YES;
FlutterMethodChannel *channel = nil;
+ (void)registerWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
#if TARGET_OS_IPHONE
if (channel == nil) {
#endif
channel = [FlutterMethodChannel
methodChannelWithName:@"com.jarvanmo/fluwx"
binaryMessenger:[registrar messenger]];
FluwxPlugin *instance = [[FluwxPlugin alloc] initWithRegistrar:registrar methodChannel:channel];
[registrar addMethodCallDelegate:instance channel:channel];
[[FluwxResponseHandler defaultManager] setMethodChannel:channel];
[registrar addApplicationDelegate:instance];
#if TARGET_OS_IPHONE
}
#endif
}
- (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar methodChannel:(FlutterMethodChannel *)flutterMethodChannel {
self = [super init];
if (self) {
_fluwxAuthHandler = [[FluwxAuthHandler alloc] initWithRegistrar:registrar methodChannel:flutterMethodChannel];
_fluwxShareHandler = [[FluwxShareHandler alloc] initWithRegistrar:registrar];
_isRunning = NO;
channel = flutterMethodChannel;
[FluwxResponseHandler defaultManager].delegate = self;
}
return self;
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
_isRunning = YES;
if ([@"registerApp" isEqualToString:call.method]) {
[self registerApp:call result:result];
} else if ([@"startLog" isEqualToString:call.method]) {
[self startLog:call result:result];
} else if ([@"stopLog" isEqualToString:call.method]) {
[self stopLog:call result:result];
} else if ([@"isWeChatInstalled" isEqualToString:call.method]) {
[self checkWeChatInstallation:call result:result];
} else if ([@"sendAuth" isEqualToString:call.method]) {
[_fluwxAuthHandler handleAuth:call result:result];
} else if ([@"authByQRCode" isEqualToString:call.method]) {
[_fluwxAuthHandler authByQRCode:call result:result];
} else if ([@"stopAuthByQRCode" isEqualToString:call.method]) {
[_fluwxAuthHandler stopAuthByQRCode:call result:result];
} else if ([@"openWXApp" isEqualToString:call.method]) {
result(@([WXApi openWXApp]));
} else if ([@"launchMiniProgram" isEqualToString:call.method]) {
[self handleLaunchMiniProgram:call result:result];
} else if ([@"subscribeMsg" isEqualToString:call.method]) {
[self handleSubscribeWithCall:call result:result];
} else if ([@"autoDeduct" isEqualToString:call.method]) {
[self handleAutoDeductWithCall:call result:result];
} else if ([@"autoDeductV2" isEqualToString:call.method]) {
[self handleautoDeductV2:call result:result];
} else if ([@"openBusinessView" isEqualToString:call.method]) {
[self handleOpenBusinessView:call result:result];
}else if([@"authByPhoneLogin" isEqualToString:call.method]){
[_fluwxAuthHandler handleAuthByPhoneLogin:call result:result];
}else if([@"getExtMsg" isEqualToString:call.method]){
[self handelGetExtMsgWithCall:call result:result];
} else if ([call.method hasPrefix:@"share"]) {
[_fluwxShareHandler handleShare:call result:result];
} else if ([@"openWeChatCustomerServiceChat" isEqualToString:call.method]) {
[self openWeChatCustomerServiceChat:call result:result];
} else if ([@"checkSupportOpenBusinessView" isEqualToString:call.method]) {
[self checkSupportOpenBusinessView:call result:result];
} else if([@"openWeChatInvoice" isEqualToString:call.method]) {
[self openWeChatInvoice:call result:result];
} else {
result(FlutterMethodNotImplemented);
}
}
- (void)openWeChatInvoice:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *appId = call.arguments[@"appId"];
if ([FluwxStringUtil isBlank:appId]) {
result([FlutterError errorWithCode:@"invalid app id" message:@"are you sure your app id is correct ? " details:appId]);
return;
}
[WXApiRequestHandler chooseInvoice: appId
timestamp:[[NSDate date] timeIntervalSince1970]
completion:^(BOOL done) {
result(@(done));
}];
}
- (void)registerApp:(FlutterMethodCall *)call result:(FlutterResult)result {
NSNumber* doOnIOS =call.arguments[@"iOS"];
if (![doOnIOS boolValue]) {
result(@NO);
return;
}
NSString *appId = call.arguments[@"appId"];
if ([FluwxStringUtil isBlank:appId]) {
result([FlutterError errorWithCode:@"invalid app id" message:@"are you sure your app id is correct ? " details:appId]);
return;
}
NSString *universalLink = call.arguments[@"universalLink"];
if ([FluwxStringUtil isBlank:universalLink]) {
result([FlutterError errorWithCode:@"invalid universal link" message:@"are you sure your universal link is correct ? " details:universalLink]);
return;
}
BOOL isWeChatRegistered = [WXApi registerApp:appId universalLink:universalLink];
result(@(isWeChatRegistered));
}
- (void)startLog:(FlutterMethodCall *)call result:(FlutterResult)result {
NSNumber *typeInt = call.arguments[@"logLevel"];
WXLogLevel logLevel = WXLogLevelDetail;
if ([typeInt isEqualToNumber:@1]) {
logLevel = WXLogLevelDetail;
} else if ([typeInt isEqualToNumber:@0]) {
logLevel = WXLogLevelNormal;
}
NSLog(@"%@",call.arguments);
[WXApi startLogByLevel:logLevel logBlock:^(NSString * _Nonnull log) {
NSLog(@"%@",log);
}];
result([NSNumber numberWithBool:true]);
}
- (void)stopLog:(FlutterMethodCall *)call result:(FlutterResult)result {
[WXApi stopLog];
result([NSNumber numberWithBool:true]);
}
- (void)checkWeChatInstallation:(FlutterMethodCall *)call result:(FlutterResult)result {
result(@([WXApi isWXAppInstalled]));
}
- (void)openWeChatCustomerServiceChat:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *url = call.arguments[@"url"];
NSString *corpId = call.arguments[@"corpId"];
WXOpenCustomerServiceReq *req = [[WXOpenCustomerServiceReq alloc] init];
req.corpid = corpId; //企业ID
req.url = url; //客服URL
return [WXApi sendReq:req completion:^(BOOL success) {
result(@(success));
}];
}
- (void)checkSupportOpenBusinessView:(FlutterMethodCall *)call result:(FlutterResult)result {
if(![WXApi isWXAppInstalled]){
result([FlutterError errorWithCode:@"WeChat Not Installed" message:@"Please install the WeChat first" details:nil]);
}else {
result(@(true));
}
}
- (void)handlePayment:(FlutterMethodCall *)call result:(FlutterResult)result {
NSNumber *timestamp = call.arguments[@"timeStamp"];
NSString *partnerId = call.arguments[@"partnerId"];
NSString *prepayId = call.arguments[@"prepayId"];
NSString *packageValue = call.arguments[@"packageValue"];
NSString *nonceStr = call.arguments[@"nonceStr"];
UInt32 timeStamp = [timestamp unsignedIntValue];
NSString *sign = call.arguments[@"sign"];
[WXApiRequestHandler sendPayment:call.arguments[@"appId"]
PartnerId:partnerId
PrepayId:prepayId
NonceStr:nonceStr
Timestamp:timeStamp
Package:packageValue
Sign:sign completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleHongKongWalletPayment:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *partnerId = call.arguments[@"prepayId"];
WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init];
req.businessType = 1;
NSMutableDictionary *queryInfoDic = [NSMutableDictionary dictionary];
[queryInfoDic setObject:partnerId forKey:@"token"];
req.queryInfoDic = queryInfoDic;
[WXApi sendReq:req completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleLaunchMiniProgram:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *userName = call.arguments[@"userName"];
NSString *path = call.arguments[@"path"];
// WXMiniProgramType *miniProgramType = call.arguments[@"miniProgramType"];
NSNumber *typeInt = call.arguments[@"miniProgramType"];
WXMiniProgramType miniProgramType = WXMiniProgramTypeRelease;
if ([typeInt isEqualToNumber:@1]) {
miniProgramType = WXMiniProgramTypeTest;
} else if ([typeInt isEqualToNumber:@2]) {
miniProgramType = WXMiniProgramTypePreview;
}
[WXApiRequestHandler launchMiniProgramWithUserName:userName
path:path
type:miniProgramType completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleSubscribeWithCall:(FlutterMethodCall *)call result:(FlutterResult)result {
NSDictionary *params = call.arguments;
NSString *appId = [params valueForKey:@"appId"];
int scene = [[params valueForKey:@"scene"] intValue];
NSString *templateId = [params valueForKey:@"templateId"];
NSString *reserved = [params valueForKey:@"reserved"];
WXSubscribeMsgReq *req = [WXSubscribeMsgReq new];
req.scene = (UInt32) scene;
req.templateId = templateId;
req.reserved = reserved;
req.openID = appId;
[WXApi sendReq:req completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleAutoDeductWithCall:(FlutterMethodCall *)call result:(FlutterResult)result {
NSMutableDictionary *paramsFromDart = [NSMutableDictionary dictionaryWithDictionary:call.arguments];
[paramsFromDart removeObjectForKey:@"businessType"];
WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init];
NSNumber *businessType = call.arguments[@"businessType"];
req.businessType = [businessType unsignedIntValue];
req.queryInfoDic = paramsFromDart;
[WXApi sendReq:req completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleautoDeductV2:(FlutterMethodCall *)call result:(FlutterResult)result {
NSMutableDictionary *paramsFromDart = call.arguments[@"queryInfo"];
// [paramsFromDart removeObjectForKey:@"businessType"];
WXOpenBusinessWebViewReq *req = [[WXOpenBusinessWebViewReq alloc] init];
NSNumber *businessType = call.arguments[@"businessType"];
req.businessType = [businessType unsignedIntValue];
req.queryInfoDic = paramsFromDart;
[WXApi sendReq:req completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handleOpenBusinessView:(FlutterMethodCall *)call result:(FlutterResult)result {
NSDictionary *params = call.arguments;
WXOpenBusinessViewReq *req = [WXOpenBusinessViewReq object];
NSString *businessType = [params valueForKey:@"businessType"];
NSString *query = [params valueForKey:@"query"];
req.businessType = businessType;
req.query = query;
req.extInfo = @"{\"miniProgramType\":0}";
[WXApi sendReq:req completion:^(BOOL done) {
result(@(done));
}];
}
- (void)handelGetExtMsgWithCall:(FlutterMethodCall *)call result:(FlutterResult)result {
result([FluwxDelegate defaultManager].extMsg);
[FluwxDelegate defaultManager].extMsg=nil;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:[FluwxResponseHandler defaultManager]];
}
// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
return [WXApi handleOpenURL:url delegate:[FluwxResponseHandler defaultManager]];
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nonnull))restorationHandler{
return [WXApi handleOpenUniversalLink:userActivity delegate:[FluwxResponseHandler defaultManager]];
}
- (void)scene:(UIScene *)scene continueUserActivity:(NSUserActivity *)userActivity API_AVAILABLE(ios(13.0)){
[WXApi handleOpenUniversalLink:userActivity delegate:[FluwxResponseHandler defaultManager]];
}
- (BOOL)handleOpenURL:(NSNotification *)aNotification {
if (handleOpenURLByFluwx) {
NSString *aURLString = [aNotification userInfo][@"url"];
NSURL *aURL = [NSURL URLWithString:aURLString];
return [WXApi handleOpenURL:aURL delegate:[FluwxResponseHandler defaultManager]];
} else {
return NO;
}
}
- (void)managerDidRecvLaunchFromWXReq:(LaunchFromWXReq *)request {
[FluwxDelegate defaultManager].extMsg = request.message.messageExt;
// LaunchFromWXReq *launchFromWXReq = (LaunchFromWXReq *)request;
//
// if (_isRunning) {
// [FluwxDelegate defaultManager].extMsg = request.message.messageExt;
// } else {
// __weak typeof(self) weakSelf = self;
// _initialWXReqRunnable = ^() {
// __strong typeof(weakSelf) strongSelf = weakSelf;
// [FluwxDelegate defaultManager].extMsg = request.message.messageExt
// };
// }
}
@end
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
#import <Flutter/Flutter.h>
#import "WXApi.h"
#import "WXApiObject.h"
@protocol WXApiManagerDelegate <NSObject>
@optional
- (void)managerDidRecvGetMessageReq:(GetMessageFromWXReq *)request;
- (void)managerDidRecvShowMessageReq:(ShowMessageFromWXReq *)request;
- (void)managerDidRecvLaunchFromWXReq:(LaunchFromWXReq *)request;
- (void)managerDidRecvMessageResponse:(SendMessageToWXResp *)response;
- (void)managerDidRecvAuthResponse:(SendAuthResp *)response;
- (void)managerDidRecvAddCardResponse:(AddCardToWXCardPackageResp *)response;
- (void)managerDidRecvChooseCardResponse:(WXChooseCardResp *)response;
- (void)managerDidRecvChooseInvoiceResponse:(WXChooseInvoiceResp *)response;
- (void)managerDidRecvSubscribeMsgResponse:(WXSubscribeMsgResp *)response;
- (void)managerDidRecvLaunchMiniProgram:(WXLaunchMiniProgramResp *)response;
- (void)managerDidRecvInvoiceAuthInsertResponse:(WXInvoiceAuthInsertResp *)response;
@end
@interface FluwxResponseHandler : NSObject <WXApiDelegate>
@property(nonatomic, assign) id <WXApiManagerDelegate> delegate;
+ (instancetype)defaultManager;
- (void)setMethodChannel:(FlutterMethodChannel *)flutterMethodChannel;
@end
//
// Created by mo on 2020/3/7.
//
#import <Flutter/Flutter.h>
#import "FluwxStringUtil.h"
#import "WXApiObject.h"
#import "FluwxResponseHandler.h"
@implementation FluwxResponseHandler
const NSString *errStr = @"errStr";
const NSString *errCode = @"errCode";
const NSString *openId = @"openId";
const NSString *type = @"type";
const NSString *lang = @"lang";
const NSString *country = @"country";
const NSString *description = @"description";
#pragma mark - LifeCycle
+ (instancetype)defaultManager {
static dispatch_once_t onceToken;
static FluwxResponseHandler *instance;
dispatch_once(&onceToken, ^{
instance = [[FluwxResponseHandler alloc] init];
});
return instance;
}
FlutterMethodChannel *fluwxMethodChannel = nil;
- (void)setMethodChannel:(FlutterMethodChannel *)flutterMethodChannel {
fluwxMethodChannel = flutterMethodChannel;
}
#pragma mark - WXApiDelegate
- (void)onResp:(BaseResp *)resp {
if ([resp isKindOfClass:[SendMessageToWXResp class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvMessageResponse:)]) {
SendMessageToWXResp *messageResp = (SendMessageToWXResp *) resp;
[_delegate managerDidRecvMessageResponse:messageResp];
}
SendMessageToWXResp *messageResp = (SendMessageToWXResp *) resp;
NSDictionary *result = @{
description: messageResp.description == nil ? @"" : messageResp.description,
errStr: messageResp.errStr == nil ? @"" : messageResp.errStr,
errCode: @(messageResp.errCode),
type: @(messageResp.type),
country: messageResp.country == nil ? @"" : messageResp.country,
lang: messageResp.lang == nil ? @"" : messageResp.lang};
[fluwxMethodChannel invokeMethod:@"onShareResponse" arguments:result];
} else if ([resp isKindOfClass:[SendAuthResp class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvAuthResponse:)]) {
SendAuthResp *authResp = (SendAuthResp *) resp;
[_delegate managerDidRecvAuthResponse:authResp];
}
SendAuthResp *authResp = (SendAuthResp *) resp;
NSDictionary *result = @{
description: authResp.description == nil ? @"" : authResp.description,
errStr: authResp.errStr == nil ? @"" : authResp.errStr,
errCode: @(authResp.errCode),
type: @(authResp.type),
country: authResp.country == nil ? @"" : authResp.country,
lang: authResp.lang == nil ? @"" : authResp.lang,
@"code": [FluwxStringUtil nilToEmpty:authResp.code],
@"state": [FluwxStringUtil nilToEmpty:authResp.state]
};
[fluwxMethodChannel invokeMethod:@"onAuthResponse" arguments:result];
} else if ([resp isKindOfClass:[AddCardToWXCardPackageResp class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvAddCardResponse:)]) {
AddCardToWXCardPackageResp *addCardResp = (AddCardToWXCardPackageResp *) resp;
[_delegate managerDidRecvAddCardResponse:addCardResp];
}
} else if ([resp isKindOfClass:[WXChooseCardResp class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvChooseCardResponse:)]) {
WXChooseCardResp *chooseCardResp = (WXChooseCardResp *) resp;
[_delegate managerDidRecvChooseCardResponse:chooseCardResp];
}
} else if ([resp isKindOfClass:[WXChooseInvoiceResp class]]) {
//TODO 处理发票返回,并回调Dart
WXChooseInvoiceResp *chooseInvoiceResp = (WXChooseInvoiceResp *) resp;
NSArray *array = chooseInvoiceResp.cardAry;
NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:array.count];
for (int i = 0; i< array.count; i++) {
WXInvoiceItem *item = array[i];
NSDictionary *dict = @{@"app_id":item.appID, @"encrypt_code":item.encryptCode, @"card_id":item.cardId};
[mutableArray addObject:dict];
}
NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:mutableArray options:NSJSONWritingPrettyPrinted error: &error];
NSString *cardItemList = @"";
if ([jsonData length] && error == nil) {
cardItemList = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
NSDictionary *result = @{
description: chooseInvoiceResp.description == nil ? @"" : chooseInvoiceResp.description,
errStr: chooseInvoiceResp.errStr == nil ? @"" : chooseInvoiceResp.errStr,
errCode: @(chooseInvoiceResp.errCode),
type: @(chooseInvoiceResp.type),
@"cardItemList":cardItemList
};
[fluwxMethodChannel invokeMethod:@"onOpenWechatInvoiceResponse" arguments:result];
} else if ([resp isKindOfClass:[WXSubscribeMsgResp class]]) {
if ([_delegate respondsToSelector:@selector(managerDidRecvSubscribeMsgResponse:)]) {
[_delegate managerDidRecvSubscribeMsgResponse:(WXSubscribeMsgResp *) resp];
}
WXSubscribeMsgResp *subscribeMsgResp = (WXSubscribeMsgResp *) resp;
NSMutableDictionary *result = [NSMutableDictionary dictionary];
NSString *openid = subscribeMsgResp.openId;
if(openid != nil && openid != NULL && ![openid isKindOfClass:[NSNull class]]){
result[@"openid"] = openid;
}
NSString *templateId = subscribeMsgResp.templateId;
if(templateId != nil && templateId != NULL && ![templateId isKindOfClass:[NSNull class]]){
result[@"templateId"] = templateId;
}
NSString *action = subscribeMsgResp.action;
if(action != nil && action != NULL && ![action isKindOfClass:[NSNull class]]){
result[@"action"] = action;
}
NSString *reserved = subscribeMsgResp.action;
if(reserved != nil && reserved != NULL && ![reserved isKindOfClass:[NSNull class]]){
result[@"reserved"] = reserved;
}
UInt32 scene = subscribeMsgResp.scene;
result[@"scene"] = @(scene);
[fluwxMethodChannel invokeMethod:@"onSubscribeMsgResp" arguments:result];
} else if ([resp isKindOfClass:[WXLaunchMiniProgramResp class]]) {
if ([_delegate respondsToSelector:@selector(managerDidRecvLaunchMiniProgram:)]) {
[_delegate managerDidRecvLaunchMiniProgram:(WXLaunchMiniProgramResp *) resp];
}
WXLaunchMiniProgramResp *miniProgramResp = (WXLaunchMiniProgramResp *) resp;
NSDictionary *commonResult = @{
description: miniProgramResp.description == nil ? @"" : miniProgramResp.description,
errStr: miniProgramResp.errStr == nil ? @"" : miniProgramResp.errStr,
errCode: @(miniProgramResp.errCode),
type: @(miniProgramResp.type),
};
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:commonResult];
if (miniProgramResp.extMsg != nil) {
result[@"extMsg"] = miniProgramResp.extMsg;
}
// @"extMsg":miniProgramResp.extMsg == nil?@"":miniProgramResp.extMsg
[fluwxMethodChannel invokeMethod:@"onLaunchMiniProgramResponse" arguments:result];
} else if ([resp isKindOfClass:[WXInvoiceAuthInsertResp class]]) {
if ([_delegate respondsToSelector:@selector(managerDidRecvInvoiceAuthInsertResponse:)]) {
[_delegate managerDidRecvInvoiceAuthInsertResponse:(WXInvoiceAuthInsertResp *) resp];
}
} else if ([resp isKindOfClass:[WXOpenBusinessWebViewResp class]]) {
WXOpenBusinessWebViewResp *businessResp = (WXOpenBusinessWebViewResp *) resp;
NSDictionary *result = @{
description: [FluwxStringUtil nilToEmpty:businessResp.description],
errStr: [FluwxStringUtil nilToEmpty:resp.errStr],
errCode: @(businessResp.errCode),
type: @(businessResp.type),
@"resultInfo": [FluwxStringUtil nilToEmpty:businessResp.result],
@"businessType": @(businessResp.businessType),
};
[fluwxMethodChannel invokeMethod:@"onWXOpenBusinessWebviewResponse" arguments:result];
}else if ([resp isKindOfClass:[WXOpenCustomerServiceResp class]]){
WXOpenCustomerServiceResp *customerResp = (WXOpenCustomerServiceResp *) resp;
NSDictionary *result = @{
description: [FluwxStringUtil nilToEmpty:customerResp.description],
errStr: [FluwxStringUtil nilToEmpty:resp.errStr],
errCode: @(customerResp.errCode),
type: @(customerResp.type),
@"extMsg":[FluwxStringUtil nilToEmpty:customerResp.extMsg]
};
[fluwxMethodChannel invokeMethod:@"onWXOpenBusinessWebviewResponse" arguments:result];
}else if ([resp isKindOfClass:[WXOpenBusinessViewResp class]]){
WXOpenBusinessViewResp *openBusinessViewResp = (WXOpenBusinessViewResp *) resp;
NSDictionary *result = @{
description: [FluwxStringUtil nilToEmpty:openBusinessViewResp.description],
errStr: [FluwxStringUtil nilToEmpty:resp.errStr],
errCode: @(openBusinessViewResp.errCode),
@"businessType":openBusinessViewResp.businessType,
type: @(openBusinessViewResp.type),
@"extMsg":[FluwxStringUtil nilToEmpty:openBusinessViewResp.extMsg]
};
[fluwxMethodChannel invokeMethod:@"onOpenBusinessViewResponse" arguments:result];
// 相关错误信息
}
}
- (void)onReq:(BaseReq *)req {
if ([req isKindOfClass:[GetMessageFromWXReq class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvGetMessageReq:)]) {
GetMessageFromWXReq *getMessageReq = (GetMessageFromWXReq *) req;
[_delegate managerDidRecvGetMessageReq:getMessageReq];
}
} else if ([req isKindOfClass:[ShowMessageFromWXReq class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvShowMessageReq:)]) {
ShowMessageFromWXReq *showMessageReq = (ShowMessageFromWXReq *) req;
[_delegate managerDidRecvShowMessageReq:showMessageReq];
}
} else if ([req isKindOfClass:[LaunchFromWXReq class]]) {
if (_delegate
&& [_delegate respondsToSelector:@selector(managerDidRecvLaunchFromWXReq:)]) {
LaunchFromWXReq *launchReq = (LaunchFromWXReq *) req;
[_delegate managerDidRecvLaunchFromWXReq:launchReq];
}
LaunchFromWXReq *launchFromWXReq = (LaunchFromWXReq *) req;
WXMediaMessage *wmm = launchFromWXReq.message;
NSString *msg = @"";
if (wmm == nil || wmm == NULL || [wmm isKindOfClass:[NSNull class]]) {
msg = @"";
}else {
msg = wmm.messageExt;
if (msg == nil || msg == NULL || [msg isKindOfClass:[NSNull class]]) {
msg = @"";
}
}
NSDictionary *result = @{
@"extMsg": msg
};
[fluwxMethodChannel invokeMethod:@"onWXShowMessageFromWX" arguments:result];
}
}
@end
//
// Created by mo on 2020/3/7.
//
#import "FluwxShareHandler.h"
#import "WXApiRequestHandler.h"
#import "FluwxStringUtil.h"
#import "NSStringWrapper.h"
#import "ThumbnailHelper.h"
@implementation FluwxShareHandler
NSString *const fluwxKeyTitle = @"title";
NSString *const fluwxKeyImage = @ "image";
NSString *const fluwxKeyImageData = @ "imageData";
NSString *const fluwxKeyThumbnail = @"thumbnail";
NSString *const fluwxKeyDescription = @"description";
NSString *const fluwxKeyPackage = @"?package=";
NSString *const fluwxKeyMessageExt = @"messageExt";
NSString *const fluwxKeyMediaTagName = @"mediaTagName ";
NSString *const fluwxKeyMessageAction = @"messageAction";
NSString *const fluwxKeyScene = @"scene";
NSString *const fluwxKeyTimeline = @"timeline";
NSString *const fluwxKeySession = @"session";
NSString *const fluwxKeyFavorite = @"favorite";
NSString *const fluwxKeyCompressThumbnail = @"compressThumbnail";
NSString *const keySource = @"source";
NSString *const keySuffix = @"suffix";
CGFloat thumbnailWidth;
NSUInteger defaultThumbnailSize = 32 * 1024;
NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
- (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar {
self = [super init];
if (self) {
_fluwxRegistrar = registrar;
thumbnailWidth = 150;
}
return self;
}
- (void)handleShare:(FlutterMethodCall *)call result:(FlutterResult)result {
if ([@"shareText" isEqualToString:call.method]) {
[self shareText:call result:result];
} else if ([@"shareImage" isEqualToString:call.method]) {
[self shareImage:call result:result];
} else if ([@"shareWebPage" isEqualToString:call.method]) {
[self shareWebPage:call result:result];
} else if ([@"shareMusic" isEqualToString:call.method]) {
[self shareMusic:call result:result];
} else if ([@"shareVideo" isEqualToString:call.method]) {
[self shareVideo:call result:result];
} else if ([@"shareMiniProgram" isEqualToString:call.method]) {
[self shareMiniProgram:call result:result];
} else if ([@"shareFile" isEqualToString:call.method]) {
[self shareFile:call result:result];
}
}
- (void)shareText:(FlutterMethodCall *)call result:(FlutterResult)result {
NSString *text = call.arguments[@"source"];
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendText:text InScene:[self intToWeChatScene:scene] completion:^(BOOL done) {
result(@(done));
}];
}
- (void)shareImage:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
NSDictionary *sourceImage = call.arguments[keySource];
NSData *sourceImageData = [self getNsDataFromWeChatFile:sourceImage];
UIImage *thumbnailImage = [self getCommonThumbnail:call];
UIImage *realThumbnailImage;
if (thumbnailImage == nil) {
NSString *suffix = sourceImage[@"suffix"];
BOOL isPNG = [self isPNG:suffix];
BOOL compress = call.arguments[fluwxKeyCompressThumbnail];
realThumbnailImage = [self getThumbnailFromNSData:sourceImageData size:defaultThumbnailSize isPNG:isPNG compress:compress];
} else {
realThumbnailImage = thumbnailImage;
}
dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendImageData:sourceImageData
TagName:call.arguments[fluwxKeyMediaTagName]
MessageExt:call.arguments[fluwxKeyMessageExt]
Action:call.arguments[fluwxKeyMessageAction]
ThumbImage:realThumbnailImage
InScene:[self intToWeChatScene:scene]
title:call.arguments[fluwxKeyTitle]
description:call.arguments[fluwxKeyDescription]
completion:^(BOOL done) {
result(@(done));
}
];
});
});
}
- (void)shareWebPage:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
UIImage *thumbnailImage = [self getCommonThumbnail:call];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *webPageUrl = call.arguments[@"webPage"];
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendLinkURL:webPageUrl
TagName:call.arguments[fluwxKeyMediaTagName]
Title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage
MessageExt:call.arguments[fluwxKeyMessageExt]
MessageAction:call.arguments[fluwxKeyMessageAction]
InScene:[self intToWeChatScene:scene]
completion:^(BOOL done) {
result(@(done));
}];
});
});
}
- (void)shareMusic:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
UIImage *thumbnailImage = [self getCommonThumbnail:call];
dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendMusicURL:call.arguments[@"musicUrl"]
dataURL:call.arguments[@"musicDataUrl"]
MusicLowBandUrl:call.arguments[@"musicLowBandUrl"]
MusicLowBandDataUrl:call.arguments[@"musicLowBandDataUrl"]
Title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage
MessageExt:call.arguments[fluwxKeyMessageExt]
MessageAction:call.arguments[fluwxKeyMessageAction]
TagName:call.arguments[fluwxKeyMediaTagName]
InScene:[self intToWeChatScene:scene]
completion:^(BOOL done) {
result(@(done));
}
];
});
});
}
- (void)shareVideo:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
UIImage *thumbnailImage = [self getCommonThumbnail:call];
dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendVideoURL:call.arguments[@"videoUrl"]
VideoLowBandUrl:call.arguments[@"videoLowBandUrl"]
Title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage
MessageExt:call.arguments[fluwxKeyMessageExt]
MessageAction:call.arguments[fluwxKeyMessageAction]
TagName:call.arguments[fluwxKeyMediaTagName]
InScene:[self intToWeChatScene:scene]
completion:^(BOOL done) {
result(@(done));
}];
});
});
}
- (void)shareFile:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
NSDictionary *sourceFile = call.arguments[keySource];
UIImage *thumbnailImage = [self getCommonThumbnail:call];
NSString *fileExtension;
NSString *suffix = sourceFile[keySuffix];
fileExtension = suffix;
if ([suffix hasPrefix:@"."]) {
NSRange range = NSMakeRange(0, 1);
fileExtension = [suffix stringByReplacingCharactersInRange:range withString:@""];
}
NSData *data = [self getNsDataFromWeChatFile:sourceFile];
dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendFileData:data
fileExtension:fileExtension
Title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage
InScene:[self intToWeChatScene:scene]
completion:^(BOOL success) {
result(@(success));
}];
});
});
}
- (void)shareMiniProgram:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{
UIImage *thumbnailImage = [self getCommonThumbnail:call];
NSData *hdImageData = nil;
NSDictionary *hdImagePath = call.arguments[@"hdImagePath"];
if (hdImagePath != (id) [NSNull null]) {
NSData *imageData = [self getNsDataFromWeChatFile:hdImagePath];
BOOL compress = call.arguments[fluwxKeyCompressThumbnail];
hdImageData = [self getThumbnailDataFromNSData:imageData size:120 * 1024 compress:compress];
// UIImage *uiImage = [self getThumbnailFromNSData:imageData size:120 * 1024 isPNG:isPNG compress:compress];
// if (isPNG) {
// hdImageData = UIImagePNGRepresentation(uiImage);
// } else {
// hdImageData = UIImageJPEGRepresentation(uiImage, 1);
// }
}
dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene];
NSNumber *typeInt = call.arguments[@"miniProgramType"];
WXMiniProgramType miniProgramType = WXMiniProgramTypeRelease;
if ([typeInt isEqualToNumber:@1]) {
miniProgramType = WXMiniProgramTypeTest;
} else if ([typeInt isEqualToNumber:@2]) {
miniProgramType = WXMiniProgramTypePreview;
}
[WXApiRequestHandler sendMiniProgramWebpageUrl:call.arguments[@"webPageUrl"]
userName:call.arguments[@"userName"]
path:call.arguments[@"path"]
title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage
hdImageData:hdImageData
withShareTicket:[call.arguments[@"withShareTicket"] boolValue]
miniProgramType:miniProgramType
MessageExt:call.arguments[fluwxKeyMessageExt]
MessageAction:call.arguments[fluwxKeyMessageAction]
TagName:call.arguments[fluwxKeyMediaTagName]
InScene:[self intToWeChatScene:scene]
completion:^(BOOL done) {
result(@(done));
}
];
});
});
}
- (UIImage *)getCommonThumbnail:(FlutterMethodCall *)call {
NSDictionary *thumbnail = call.arguments[fluwxKeyThumbnail];
if (thumbnail == nil || thumbnail == (id) [NSNull null]) {
return nil;
}
NSString *suffix = thumbnail[@"suffix"];
NSNumber* compress = call.arguments[fluwxKeyCompressThumbnail];
NSData *thumbnailData = [self getNsDataFromWeChatFile:thumbnail];
UIImage *thumbnailImage = [self getThumbnailFromNSData:thumbnailData size:defaultThumbnailSize isPNG:[self isPNG:suffix] compress:[compress boolValue]];
return thumbnailImage;
}
//enum ImageSchema {
// NETWORK,
// ASSET,
// FILE,
// BINARY,
//}
- (NSData *)getNsDataFromWeChatFile:(NSDictionary *)weChatFile {
NSNumber *schema = weChatFile[@"schema"];
if ([schema isEqualToNumber:@0]) {
NSString *source = weChatFile[keySource];
NSURL *imageURL = [NSURL URLWithString:source];
//下载图片
return [NSData dataWithContentsOfURL:imageURL];
} else if ([schema isEqualToNumber:@1]) {
NSString *source = weChatFile[keySource];
return [NSData dataWithContentsOfFile:[self readFileFromAssets:source]];
} else if ([schema isEqualToNumber:@2]) {
NSString *source = weChatFile[keySource];
return [NSData dataWithContentsOfFile:source];
} else if ([schema isEqualToNumber:@3]) {
FlutterStandardTypedData *imageData = weChatFile[@"source"];
return imageData.data;
} else {
return nil;
}
}
- (UIImage *)getThumbnailFromNSData:(NSData *)data size:(NSUInteger)size isPNG:(BOOL)isPNG compress:(BOOL)compress{
UIImage *uiImage = [UIImage imageWithData:data];
if(compress)
return [ThumbnailHelper compressImage:uiImage toByte:size isPNG:isPNG];
else
return uiImage;
}
- (NSData *)getThumbnailDataFromNSData:(NSData *)data size:(NSUInteger)size compress:(BOOL)compress {
if(compress) {
return [ThumbnailHelper compressImageData:data toByte:size];
} else{
return data;
}
}
- (NSString *)readFileFromAssets:(NSString *)imagePath {
NSArray *array = [self formatAssets:imagePath];
NSString *key;
if ([FluwxStringUtil isBlank:array[1]]) {
key = [_fluwxRegistrar lookupKeyForAsset:array[0]];
} else {
key = [_fluwxRegistrar lookupKeyForAsset:array[0] fromPackage:array[1]];
}
return [[NSBundle mainBundle] pathForResource:key ofType:nil];
}
- (NSArray *)formatAssets:(NSString *)originPath {
NSString *path = nil;
NSString *packageName = @"";
NSString *pathWithoutSchema = originPath;
NSInteger indexOfPackage = [pathWithoutSchema lastIndexOfString:@"?package="];
if (indexOfPackage != JavaNotFound) {
path = [pathWithoutSchema substringFromIndex:0 toIndex:indexOfPackage];
NSInteger begin = indexOfPackage + [fluwxKeyPackage length];
packageName = [pathWithoutSchema substringFromIndex:begin toIndex:[pathWithoutSchema length]];
} else {
path = pathWithoutSchema;
}
return @[path, packageName];
}
- (BOOL)isPNG:(NSString *)suffix {
return [@".png" equals:suffix];
}
- (enum WXScene)intToWeChatScene:(NSNumber *)value {
// enum WeChatScene { SESSION, TIMELINE, FAVORITE }
if ([value isEqual: @0]) {
return WXSceneSession;
} else if ([value isEqual: @1]) {
return WXSceneTimeline;
} else if ([value isEqual: @2]) {
return WXSceneFavorite;
} else {
return WXSceneSession;
}
}
@end
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
@interface FluwxStringUtil : NSObject
+ (BOOL)isBlank:(NSString *)string;
+ (NSString *)nilToEmpty:(NSString *)string;
@end
\ No newline at end of file
//
// Created by mo on 2020/3/7.
//
#import "FluwxStringUtil.h"
@implementation FluwxStringUtil
+ (BOOL)isBlank:(NSString *)string {
if (string == nil) {
return YES;
}
if ([string isKindOfClass:[NSNull class]]) {
return YES;
}
return [[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0;
}
+ (NSString *)nilToEmpty:(NSString *)string {
return string == nil ? @"" : string;
}
@end
\ No newline at end of file
//
// Created by mo on 2020/3/8.
//
#import <Foundation/Foundation.h>
#define JavaNotFound -1
@interface NSString (Wrapper)
/** Return the char value at the specified index. */
- (unichar)charAt:(int)index;
/**
* Compares two strings lexicographically.
* the value 0 if the argument string is equal to this string;
* a value less than 0 if this string is lexicographically less than the string argument;
* and a value greater than 0 if this string is lexicographically greater than the string argument.
*/
- (int)compareTo:(NSString *)anotherString;
- (int)compareToIgnoreCase:(NSString *)str;
- (BOOL)contains:(NSString *)str;
- (BOOL)startsWith:(NSString *)prefix;
- (BOOL)endsWith:(NSString *)suffix;
- (BOOL)equals:(NSString *)anotherString;
- (BOOL)equalsIgnoreCase:(NSString *)anotherString;
- (int)indexOfChar:(unichar)ch;
- (int)indexOfChar:(unichar)ch fromIndex:(int)index;
- (int)indexOfString:(NSString *)str;
- (int)indexOfString:(NSString *)str fromIndex:(int)index;
- (int)lastIndexOfChar:(unichar)ch;
- (int)lastIndexOfChar:(unichar)ch fromIndex:(int)index;
- (int)lastIndexOfString:(NSString *)str;
- (int)lastIndexOfString:(NSString *)str fromIndex:(int)index;
- (NSString *)substringFromIndex:(NSInteger)beginIndex
toIndex:(NSInteger)endIndex;
- (NSString *)toLowerCase;
- (NSString *)toUpperCase;
- (NSString *)trim;
- (NSString *)replaceAll:(NSString *)origin with:(NSString *)replacement;
- (NSArray *)split:(NSString *)separator;
@end
//
// Created by mo on 2020/3/8.
//
#import "NSStringWrapper.h"
@implementation NSString (Wrapper)
/** Java-like method. Returns the char value at the specified index. */
- (unichar)charAt:(int)index {
return [self characterAtIndex:index];
}
/**
* Java-like method. Compares two strings lexicographically.
* the value 0 if the argument string is equal to this string;
* a value less than 0 if this string is lexicographically less than the string argument;
* and a value greater than 0 if this string is lexicographically greater than the string argument.
*/
- (int)compareTo:(NSString *)anotherString {
return (int)[self compare:anotherString];
}
/** Java-like method. Compares two strings lexicographically, ignoring case differences. */
- (int)compareToIgnoreCase:(NSString *)str {
return (int)[self compare:str options:NSCaseInsensitiveSearch];
}
/** Java-like method. Returns true if and only if this string contains the specified sequence of char values. */
- (BOOL)contains:(NSString *)str {
NSRange range = [self rangeOfString:str];
return (range.location != NSNotFound);
}
- (BOOL)startsWith:(NSString *)prefix {
return [self hasPrefix:prefix];
}
- (BOOL)endsWith:(NSString *)suffix {
return [self hasSuffix:suffix];
}
- (BOOL)equals:(NSString *)anotherString {
return [self isEqualToString:anotherString];
}
- (BOOL)equalsIgnoreCase:(NSString *)anotherString {
return [[self toLowerCase] equals:[anotherString toLowerCase]];
}
- (int)indexOfChar:(unichar)ch {
return [self indexOfChar:ch fromIndex:0];
}
- (int)indexOfChar:(unichar)ch fromIndex:(int)index {
int len = (int)self.length;
for (int i = index; i < len; ++i) {
if (ch == [self charAt:i]) {
return i;
}
}
return JavaNotFound;
}
- (int)indexOfString:(NSString *)str {
NSRange range = [self rangeOfString:str];
if (range.location == NSNotFound) {
return JavaNotFound;
}
return (int)range.location;
}
- (int)indexOfString:(NSString *)str fromIndex:(int)index {
NSRange fromRange = NSMakeRange(index, self.length - index);
NSRange range = [self rangeOfString:str options:NSLiteralSearch range:fromRange];
if (range.location == NSNotFound) {
return JavaNotFound;
}
return (int)range.location;
}
- (int)lastIndexOfChar:(unichar)ch {
int len = (int)self.length;
for (int i = len - 1; i >= 0; --i) {
if ([self charAt:i] == ch) {
return i;
}
}
return JavaNotFound;
}
- (int)lastIndexOfChar:(unichar)ch fromIndex:(int)index {
int len = (int)self.length;
if (index >= len) {
index = len - 1;
}
for (int i = index; i >= 0; --i) {
if ([self charAt:i] == ch) {
return index;
}
}
return JavaNotFound;
}
- (int)lastIndexOfString:(NSString *)str {
NSRange range = [self rangeOfString:str options:NSBackwardsSearch];
if (range.location == NSNotFound) {
return JavaNotFound;
}
return (int)range.location;
}
- (int)lastIndexOfString:(NSString *)str fromIndex:(int)index {
NSRange fromRange = NSMakeRange(0, index);
NSRange range = [self rangeOfString:str options:NSBackwardsSearch range:fromRange];
if (range.location == NSNotFound) {
return JavaNotFound;
}
return (int)range.location;
}
- (NSString *)substringFromIndex:(NSInteger)beginIndex
toIndex:(NSInteger)endIndex {
if (endIndex <= beginIndex) {
return @"";
}
NSRange range = NSMakeRange(beginIndex, endIndex - beginIndex);
return [self substringWithRange:range];
}
- (NSString *)toLowerCase {
return [self lowercaseString];
}
- (NSString *)toUpperCase {
return [self uppercaseString];
}
- (NSString *)trim {
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (NSString *)replaceAll:(NSString *)origin with:(NSString *)replacement {
return [self stringByReplacingOccurrencesOfString:origin withString:replacement];
}
- (NSArray *)split:(NSString *)separator {
return [self componentsSeparatedByString:separator];
}
@end
//
// SendMessageToWXReq+requestWithTextOrMediaMessage.h
// SDKSample
//
// Created by Jeason on 15/7/14.
//
//
#import "WXApiObject.h"
@interface SendMessageToWXReq (requestWithTextOrMediaMessage)
+ (SendMessageToWXReq *)requestWithText:(NSString *)text
OrMediaMessage:(WXMediaMessage *)message
bText:(BOOL)bText
InScene:(enum WXScene)scene;
@end
//
// SendMessageToWXReq+requestWithTextOrMediaMessage.m
// SDKSample
//
// Created by Jeason on 15/7/14.
//
//
#import "SendMessageToWXReq+requestWithTextOrMediaMessage.h"
@implementation SendMessageToWXReq (requestWithTextOrMediaMessage)
+ (SendMessageToWXReq *)requestWithText:(NSString *)text
OrMediaMessage:(WXMediaMessage *)message
bText:(BOOL)bText
InScene:(enum WXScene)scene {
SendMessageToWXReq *req = [[SendMessageToWXReq alloc] init];
req.bText = bText;
req.scene = scene;
if (bText)
req.text = text;
else
req.message = message;
return req;
}
@end
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
@interface ThumbnailHelper : NSObject
+ (UIImage *)compressImage:(UIImage *)image toByte:(NSUInteger)maxLength isPNG:(BOOL)isPNG;
/// NSData 压缩后转NSData
/// @param imageData 来源data
/// @param maxLength 压缩目标值,压缩结果在maxLength的0.9~1之间
+ (NSData *)compressImageData:(NSData *)imageData toByte:(NSUInteger)maxLength;
@end
//
// Created by mo on 2020/3/7.
//
#import "ThumbnailHelper.h"
@implementation ThumbnailHelper
+ (NSData *)compressImageData:(NSData *)imageData toByte:(NSUInteger)maxLength {
// Compress by quality
CGFloat compression = 1;
NSData *data = imageData;
NSLog(@"压缩前 %lu %lu ",(unsigned long)data.length,maxLength);
if (data.length < maxLength) return data;
UIImage *image = [UIImage imageWithData:imageData];
CGFloat max = 1;
CGFloat min = 0;
for (int i = 0; i < 6; ++i) {
compression = (max + min) / 2;
data = UIImageJPEGRepresentation(image, compression);
if (data.length < maxLength * 0.9) {
min = compression;
} else if (data.length > maxLength) {
max = compression;
} else {
break;
}
}
NSLog(@"压缩第一次 %lu %lu ",(unsigned long)data.length,maxLength);
if (data.length < maxLength) return data;
UIImage *resultImage;
resultImage = [UIImage imageWithData:data];
// Compress by size
NSUInteger lastDataLength = 0;
while (data.length > maxLength && data.length != lastDataLength) {
lastDataLength = data.length;
CGFloat ratio = (CGFloat) maxLength / data.length;
CGSize size = CGSizeMake((NSUInteger) (resultImage.size.width * sqrtf(ratio)),
(NSUInteger) (resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
UIGraphicsBeginImageContext(size);
[resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
data = UIImageJPEGRepresentation(resultImage, compression);
}
NSLog(@"压缩第二次%lu %lu ",(unsigned long)data.length,maxLength);
return data;
}
+ (UIImage *)compressImage:(UIImage *)image toByte:(NSUInteger)maxLength isPNG:(BOOL)isPNG {
// Compress by quality
CGFloat compression = 1;
NSData *data = UIImageJPEGRepresentation(image, compression);
if (data.length < maxLength) return image;
CGFloat max = 1;
CGFloat min = 0;
for (int i = 0; i < 6; ++i) {
compression = (max + min) / 2;
data = UIImageJPEGRepresentation(image, compression);
if (data.length < maxLength * 0.9) {
min = compression;
} else if (data.length > maxLength) {
max = compression;
} else {
break;
}
}
UIImage *resultImage;
if (isPNG) {
NSData *tmp = UIImagePNGRepresentation([UIImage imageWithData:data]);
resultImage = [UIImage imageWithData:tmp];
} else {
resultImage = [UIImage imageWithData:data];
}
if (data.length < maxLength) return resultImage;
// Compress by size
NSUInteger lastDataLength = 0;
while (data.length > maxLength && data.length != lastDataLength) {
lastDataLength = data.length;
CGFloat ratio = (CGFloat) maxLength / data.length;
CGSize size = CGSizeMake((NSUInteger) (resultImage.size.width * sqrtf(ratio)),
(NSUInteger) (resultImage.size.height * sqrtf(ratio))); // Use NSUInteger to prevent white blank
UIGraphicsBeginImageContext(size);
[resultImage drawInRect:CGRectMake(0, 0, size.width, size.height)];
resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
data = UIImageJPEGRepresentation(resultImage, compression);
}
return resultImage;
}
- (UIImage *)scaleFromImage:(UIImage *)image width:(CGSize)newSize {
CGSize imageSize = image.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
if (width <= newSize.width && height <= newSize.height) {
return image;
}
if (width == 0 || height == 0) {
return image;
}
CGFloat widthFactor = newSize.width / width;
CGFloat heightFactor = newSize.height / height;
CGFloat scaleFactor = (widthFactor < heightFactor ? widthFactor : heightFactor);
CGFloat scaledWidth = width * scaleFactor;
CGFloat scaledHeight = height * scaleFactor;
CGSize targetSize = CGSizeMake(scaledWidth, scaledHeight);
UIGraphicsBeginImageContext(targetSize);
[image drawInRect:CGRectMake(0, 0, scaledWidth, scaledHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end
//
// WXApi.h
// 所有Api接口
//
// Created by Wechat on 12-2-28.
// Copyright (c) 2012年 Tencent. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "WXApiObject.h"
NS_ASSUME_NONNULL_BEGIN
#pragma mark - WXApiDelegate
/*! @brief 接收并处理来自微信终端程序的事件消息
*
* 接收并处理来自微信终端程序的事件消息,期间微信界面会切换到第三方应用程序。
* WXApiDelegate 会在handleOpenURL:delegate:中使用并触发。
*/
@protocol WXApiDelegate <NSObject>
@optional
/*! @brief 收到一个来自微信的请求,第三方应用程序处理完后调用sendResp向微信发送结果
*
* 收到一个来自微信的请求,异步处理完成后必须调用sendResp发送处理结果给微信。
* 可能收到的请求有GetMessageFromWXReq、ShowMessageFromWXReq等。
* @param req 具体请求内容,是自动释放的
*/
- (void)onReq:(BaseReq*)req;
/*! @brief 发送一个sendReq后,收到微信的回应
*
* 收到一个来自微信的处理结果。调用一次sendReq后会收到onResp。
* 可能收到的处理结果有SendMessageToWXResp、SendAuthResp等。
* @param resp具体的回应内容,是自动释放的
*/
- (void)onResp:(BaseResp*)resp;
@end
#pragma mark - WXApiLogDelegate
@protocol WXApiLogDelegate <NSObject>
- (void)onLog:(NSString*)log logLevel:(WXLogLevel)level;
@end
#pragma mark - WXApi
/*! @brief 微信Api接口函数类
*
* 该类封装了微信终端SDK的所有接口
*/
@interface WXApi : NSObject
/*! @brief WXApi的成员函数,向微信终端程序注册第三方应用。
*
* 需要在每次启动第三方应用程序时调用。
* @attention 请保证在主线程中调用此函数
* @param appid 微信开发者ID
* @param universalLink 微信开发者Universal Link
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)registerApp:(NSString *)appid universalLink:(NSString *)universalLink;
/*! @brief 处理旧版微信通过URL启动App时传递的数据
*
* 需要在 application:openURL:sourceApplication:annotation:或者application:handleOpenURL中调用。
* @param url 微信启动第三方应用时传递过来的URL
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)handleOpenURL:(NSURL *)url delegate:(nullable id<WXApiDelegate>)delegate;
/*! @brief 处理微信通过Universal Link启动App时传递的数据
*
* 需要在 application:continueUserActivity:restorationHandler:中调用。
* @param userActivity 微信启动第三方应用时系统API传递过来的userActivity
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)handleOpenUniversalLink:(NSUserActivity *)userActivity delegate:(nullable id<WXApiDelegate>)delegate;
/*! @brief 检查微信是否已被用户安装
*
* @return 微信已安装返回YES,未安装返回NO。
*/
+ (BOOL)isWXAppInstalled;
/*! @brief 判断当前微信的版本是否支持OpenApi
*
* @return 支持返回YES,不支持返回NO。
*/
+ (BOOL)isWXAppSupportApi;
/*! @brief 判断当前微信的版本是否支持分享微信状态功能
*
* @attention 需在工程LSApplicationQueriesSchemes配置中添加weixinStateAPI
* @return 支持返回YES,不支持返回NO。
*/
+ (BOOL)isWXAppSupportStateAPI;
/*! @brief 获取微信的itunes安装地址
*
* @return 微信的安装地址字符串。
*/
+ (NSString *)getWXAppInstallUrl;
/*! @brief 获取当前微信SDK的版本号
*
* @return 返回当前微信SDK的版本号
*/
+ (NSString *)getApiVersion;
/*! @brief 打开微信
*
* @return 成功返回YES,失败返回NO。
*/
+ (BOOL)openWXApp;
/*! @brief 发送请求到微信,等待微信返回onResp
*
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持以下类型
* SendAuthReq、SendMessageToWXReq、PayReq等。
* @param req 具体的发送请求。
* @param completion 调用结果回调block
*/
+ (void)sendReq:(BaseReq *)req completion:(void (^ __nullable)(BOOL success))completion;
/*! @brief 收到微信onReq的请求,发送对应的应答给微信,并切换到微信界面
*
* 函数调用后,会切换到微信的界面。第三方应用程序收到微信onReq的请求,异步处理该请求,完成后必须调用该函数。可能发送的相应有
* GetMessageFromWXResp、ShowMessageFromWXResp等。
* @param resp 具体的应答内容
* @param completion 调用结果回调block
*/
+ (void)sendResp:(BaseResp*)resp completion:(void (^ __nullable)(BOOL success))completion;
/*! @brief 发送Auth请求到微信,支持用户没安装微信,等待微信返回onResp
*
* 函数调用后,会切换到微信的界面。第三方应用程序等待微信返回onResp。微信在异步处理完成后一定会调用onResp。支持SendAuthReq类型。
* @param req 具体的发送请求。
* @param viewController 当前界面对象。
* @param delegate WXApiDelegate对象,用来接收微信触发的消息。
* @param completion 调用结果回调block
*/
+ (void)sendAuthReq:(SendAuthReq *)req viewController:(UIViewController*)viewController delegate:(nullable id<WXApiDelegate>)delegate completion:(void (^ __nullable)(BOOL success))completion;
/*! @brief 测试函数,用于排查当前App通过Universal Link方式分享到微信的流程
注意1: 调用自检函数之前必须要先调用registerApp:universalLink接口, 并确认调用成功
注意2: 自检过程中会有Log产生,可以先调用startLogByLevel函数,根据Log排查问题
注意3: 会多次回调block
注意4: 仅用于新接入SDK时调试使用,请勿在正式环境的调用
*
* 当completion回调的step为WXULCheckStepFinal时,表示检测通过,Universal Link接入成功
* @param completion 回调Block
*/
+ (void)checkUniversalLinkReady:(nonnull WXCheckULCompletion)completion;
/*! @brief WXApi的成员函数,接受微信的log信息。byBlock
注意1:SDK会强引用这个block,注意不要导致内存泄漏,注意不要导致内存泄漏
注意2:调用过一次startLog by block之后,如果再调用一次任意方式的startLoad,会释放上一次logBlock,不再回调上一个logBlock
*
* @param level 打印log的级别
* @param logBlock 打印log的回调block
*/
+ (void)startLogByLevel:(WXLogLevel)level logBlock:(WXLogBolock)logBlock;
/*! @brief WXApi的成员函数,接受微信的log信息。byDelegate
注意1:sdk会弱引用这个delegate,这里可加任意对象为代理,不需要与WXApiDelegate同一个对象
注意2:调用过一次startLog by delegate之后,再调用一次任意方式的startLoad,不会再回调上一个logDelegate对象
* @param level 打印log的级别
* @param logDelegate 打印log的回调代理,
*/
+ (void)startLogByLevel:(WXLogLevel)level logDelegate:(id<WXApiLogDelegate>)logDelegate;
/*! @brief 停止打印log,会清理block或者delegate为空,释放block
* @param
*/
+ (void)stopLog;
@end
NS_ASSUME_NONNULL_END
//
// MMApiObject.h
// Api对象,包含所有接口和对象数据定义
//
// Created by Wechat on 12-2-28.
// Copyright (c) 2012年 Tencent. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/*! @brief 错误码
*
*/
enum WXErrCode {
WXSuccess = 0, /**< 成功 */
WXErrCodeCommon = -1, /**< 普通错误类型 */
WXErrCodeUserCancel = -2, /**< 用户点击取消并返回 */
WXErrCodeSentFail = -3, /**< 发送失败 */
WXErrCodeAuthDeny = -4, /**< 授权失败 */
WXErrCodeUnsupport = -5, /**< 微信不支持 */
};
/*! @brief 请求发送场景
*
*/
enum WXScene {
WXSceneSession = 0, /**< 聊天界面 */
WXSceneTimeline = 1, /**< 朋友圈 */
WXSceneFavorite = 2, /**< 收藏 */
WXSceneSpecifiedSession = 3, /**< 指定联系人 */
WXSceneState = 4, /**< 状态 */
};
enum WXAPISupport {
WXAPISupportSession = 0,
};
/*! @brief 跳转profile类型
*
*/
enum WXBizProfileType {
WXBizProfileType_Normal = 0, //**< 普通公众号 */
WXBizProfileType_Device = 1, //**< 硬件公众号 */
};
/*! @brief 分享小程序类型
*
*/
typedef NS_ENUM(NSUInteger, WXMiniProgramType) {
WXMiniProgramTypeRelease = 0, //**< 正式版 */
WXMiniProgramTypeTest = 1, //**< 开发版 */
WXMiniProgramTypePreview = 2, //**< 体验版 */
};
/*! @brief 跳转mp网页类型
*
*/
enum WXMPWebviewType {
WXMPWebviewType_Ad = 0, /**< 广告网页 **/
};
/*! @brief log的级别
*
*/
typedef NS_ENUM(NSInteger,WXLogLevel) {
WXLogLevelNormal = 0, // 打印日常的日志
WXLogLevelDetail = 1, // 打印详细的日志
};
/*! @brief 打印回调的block
*
*/
typedef void(^WXLogBolock)(NSString *log);
/*! @brief 微信Universal Link检查函数 (WXApi#checkUniversalLinkReady:),检查步骤枚举值
*
* WXULCheckStepParams 参数检测
* WXULCheckStepSystemVersion 当前系统版本检测
* WXULCheckStepWechatVersion 微信客户端版本检测
* WXULCheckStepSDKInnerOperation 微信SDK内部操作检测
* WXULCheckStepLaunchWechat App拉起微信检测
* WXULCheckStepBackToCurrentApp 由微信返回当前App检测
* WXULCheckStepFinal 最终结果
*/
typedef NS_ENUM(NSInteger, WXULCheckStep)
{
WXULCheckStepParams,
WXULCheckStepSystemVersion,
WXULCheckStepWechatVersion,
WXULCheckStepSDKInnerOperation,
WXULCheckStepLaunchWechat,
WXULCheckStepBackToCurrentApp,
WXULCheckStepFinal,
};
#pragma mark - WXCheckULStepResult
/*! @brief 该类为微信Universal Link检测函数结果类
*
*/
@interface WXCheckULStepResult : NSObject
/** 是否成功 */
@property(nonatomic, assign) BOOL success;
/** 当前错误信息 */
@property(nonatomic, strong) NSString* errorInfo;
/** 修正建议 */
@property(nonatomic, strong) NSString* suggestion;
- (instancetype)initWithCheckResult:(BOOL)success errorInfo:(nullable NSString*)errorInfo suggestion:(nullable NSString*)suggestion;
@end
/*! @brief 微信Universal Link检查函数 (WXApi#checkUniversalLinkReady:),回调Block
*
* @param step 当前检测步骤
* @param result 检测结果
*/
typedef void(^WXCheckULCompletion)(WXULCheckStep step, WXCheckULStepResult* result);
#pragma mark - BaseReq
/*! @brief 该类为微信终端SDK所有请求类的基类
*
*/
@interface BaseReq : NSObject
/** 请求类型 */
@property (nonatomic, assign) int type;
/** 由用户微信号和AppID组成的唯一标识,需要校验微信用户是否换号登录时填写*/
@property (nonatomic, copy) NSString *openID;
@end
#pragma mark - BaseResp
/*! @brief 该类为微信终端SDK所有响应类的基类
*
*/
@interface BaseResp : NSObject
/** 错误码 */
@property (nonatomic, assign) int errCode;
/** 错误提示字符串 */
@property (nonatomic, copy) NSString *errStr;
/** 响应类型 */
@property (nonatomic, assign) int type;
@end
#pragma mark - WXMediaMessage
@class WXMediaMessage;
#pragma mark - SendAuthReq
/*! @brief 第三方程序向微信终端请求认证的消息结构
*
* 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数,
* 向微信终端发送一个SendAuthReq消息结构。微信终端处理完后会向第三方程序发送一个处理结果。
* @see SendAuthResp
*/
@interface SendAuthReq : BaseReq
/** 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数,向微信终端发送一个SendAuthReq消息结构。微信终端处理完后会向第三方程序发送一个处理结果。
* @see SendAuthResp
* @note scope字符串长度不能超过1K
*/
@property (nonatomic, copy) NSString *scope;
/** 第三方程序本身用来标识其请求的唯一性,最后跳转回第三方程序时,由微信终端回传。
* @note state字符串长度不能超过1K
*/
@property (nonatomic, copy) NSString *state;
@end
#pragma mark - SendAuthResp
/*! @brief 微信处理完第三方程序的认证和权限申请后向第三方程序回送的处理结果。
*
* 第三方程序要向微信申请认证,并请求某些权限,需要调用WXApi的sendReq成员函数,向微信终端发送一个SendAuthReq消息结构。
* 微信终端处理完后会向第三方程序发送一个SendAuthResp。
* @see onResp
*/
@interface SendAuthResp : BaseResp
@property (nonatomic, copy, nullable) NSString *code;
/** 第三方程序发送时用来标识其请求的唯一性的标志,由第三方程序调用sendReq时传入,由微信终端回传
* @note state字符串长度不能超过1K
*/
@property (nonatomic, copy, nullable) NSString *state;
@property (nonatomic, copy, nullable) NSString *lang;
@property (nonatomic, copy, nullable) NSString *country;
@end
#pragma mark - WXStateJumpInfo
/*! @brief 状态发表时的小尾巴跳转信息
*/
@interface WXStateJumpInfo : NSObject
@end
#pragma mark - WXStateJumpUrlInfo
/*! @brief 状态小尾巴跳转指定url的信息
*/
@interface WXStateJumpUrlInfo : WXStateJumpInfo
/** 跳转到指定的url
* @note 必填,url长度必须大于0且小于10K
*/
@property (nonatomic, copy) NSString *url;
@end
#pragma mark - WXStateSceneDataObject
/*! @brief 场景类型额外参数基类
*/
@interface WXSceneDataObject : NSObject
@end
#pragma mark - WXStateSceneDataObject
/*! @brief 状态场景类型
* 用户填写WXStateSceneDataObject参数后,可以跳转到微信状态发表页
*/
@interface WXStateSceneDataObject : WXSceneDataObject
/** 状态标志的ID
* @note 选填,文本长度必须小于10K
*/
@property (nonatomic, copy) NSString *stateId;
/** 状态发表时附带的文本描述
* @note 选填,文本长度必须小于10K
*/
@property (nonatomic, copy) NSString *stateTitle;
/** 后台校验token
* @note 选填,文本长度必须小于10K
*/
@property (nonatomic, copy) NSString *token;
/** 小尾巴跳转所需的信息
* @note 必填,目前仅支持url跳转
*/
@property (nonatomic, strong) WXStateJumpInfo *stateJumpDataInfo;
@end
#pragma mark - SendMessageToWXReq
/*! @brief 第三方程序发送消息至微信终端程序的消息结构体
*
* 第三方程序向微信发送信息需要传入SendMessageToWXReq结构体,信息类型包括文本消息和多媒体消息,
* 分别对应于text和message成员。调用该方法后,微信处理完信息会向第三方程序发送一个处理结果。
* @see SendMessageToWXResp
*/
@interface SendMessageToWXReq : BaseReq
/** 发送消息的文本内容
* @note 文本长度必须大于0且小于10K
*/
@property (nonatomic, copy) NSString *text;
/** 发送消息的多媒体内容
* @see WXMediaMessage
*/
@property (nonatomic, strong) WXMediaMessage *message;
/** 发送消息的类型,包括文本消息和多媒体消息两种,两者只能选择其一,不能同时发送文本和多媒体消息 */
@property (nonatomic, assign) BOOL bText;
/** 发送的目标场景,可以选择发送到会话(WXSceneSession)或者朋友圈(WXSceneTimeline)。 默认发送到会话。
* @see WXScene
*/
@property (nonatomic, assign) int scene;
/** 指定发送消息的人
* @note WXSceneSpecifiedSession时有效
*/
@property (nonatomic, copy, nullable) NSString *toUserOpenId;
/** 目标场景附带信息
* @note 目前只针对状态场景
*/
@property (nonatomic, strong) WXSceneDataObject *sceneDataObject;
@end
#pragma mark - SendMessageToWXResp
/*! @brief 微信终端向第三方程序返回的SendMessageToWXReq处理结果。
*
* 第三方程序向微信终端发送SendMessageToWXReq后,微信发送回来的处理结果,该结果用SendMessageToWXResp表示。
*/
@interface SendMessageToWXResp : BaseResp
@property(nonatomic, copy) NSString *lang;
@property(nonatomic, copy) NSString *country;
@end
#pragma mark - GetMessageFromWXReq
/*! @brief 微信终端向第三方程序请求提供内容的消息结构体。
*
* 微信终端向第三方程序请求提供内容,微信终端会向第三方程序发送GetMessageFromWXReq消息结构体,
* 需要第三方程序调用sendResp返回一个GetMessageFromWXResp消息结构体。
*/
@interface GetMessageFromWXReq : BaseReq
@property (nonatomic, strong) NSString *lang;
@property (nonatomic, strong) NSString *country;
@end
#pragma mark - GetMessageFromWXResp
/*! @brief 微信终端向第三方程序请求提供内容,第三方程序向微信终端返回的消息结构体。
*
* 微信终端向第三方程序请求提供内容,第三方程序调用sendResp向微信终端返回一个GetMessageFromWXResp消息结构体。
*/
@interface GetMessageFromWXResp : BaseResp
/** 向微信终端提供的文本内容
@note 文本长度必须大于0且小于10K
*/
@property (nonatomic, strong) NSString *text;
/** 向微信终端提供的多媒体内容。
* @see WXMediaMessage
*/
@property (nonatomic, strong) WXMediaMessage *message;
/** 向微信终端提供内容的消息类型,包括文本消息和多媒体消息两种,两者只能选择其一,不能同时发送文本和多媒体消息 */
@property (nonatomic, assign) BOOL bText;
@end
#pragma mark - ShowMessageFromWXReq
/*! @brief 微信通知第三方程序,要求第三方程序显示的消息结构体。
*
* 微信需要通知第三方程序显示或处理某些内容时,会向第三方程序发送ShowMessageFromWXReq消息结构体。
* 第三方程序处理完内容后调用sendResp向微信终端发送ShowMessageFromWXResp。
*/
@interface ShowMessageFromWXReq : BaseReq
/** 微信终端向第三方程序发送的要求第三方程序处理的多媒体内容
* @see WXMediaMessage
*/
@property (nonatomic, strong) WXMediaMessage *message;
@property (nonatomic, copy) NSString *lang;
@property (nonatomic, copy) NSString *country;
@end
#pragma mark - ShowMessageFromWXResp
/*! @brief 微信通知第三方程序,要求第三方程序显示或处理某些消息,第三方程序处理完后向微信终端发送的处理结果。
*
* 微信需要通知第三方程序显示或处理某些内容时,会向第三方程序发送ShowMessageFromWXReq消息结构体。
* 第三方程序处理完内容后调用sendResp向微信终端发送ShowMessageFromWXResp。
*/
@interface ShowMessageFromWXResp : BaseResp
@end
#pragma mark - LaunchFromWXReq
/*! @brief 微信终端打开第三方程序携带的消息结构体
*
* 微信向第三方发送的结构体,第三方不需要返回
*/
@interface LaunchFromWXReq : BaseReq
@property (nonatomic, strong) WXMediaMessage *message;
@property (nonatomic, copy) NSString *lang;
@property (nonatomic, copy) NSString *country;
@end
#pragma mark - OpenWebviewReq
/* ! @brief 第三方通知微信启动内部浏览器,打开指定网页
*
* 第三方通知微信启动内部浏览器,打开指定Url对应的网页
*/
@interface OpenWebviewReq : BaseReq
/** 需要打开的网页对应的Url
* @attention 长度不能超过1024
*/
@property(nonatomic, copy) NSString *url;
@end
#pragma mark - OpenWebviewResp
/*! @brief 微信终端向第三方程序返回的OpenWebviewReq处理结果
*
* 第三方程序向微信终端发送OpenWebviewReq后,微信发送回来的处理结果,该结果用OpenWebviewResp表示
*/
@interface OpenWebviewResp : BaseResp
@end
#pragma mark - WXOpenBusinessWebViewReq
/*! @brief 第三方通知微信启动内部浏览器,打开指定业务的网页
*
*
*/
@interface WXOpenBusinessWebViewReq : BaseReq
/** 网页业务类型
* @attention
*/
@property (nonatomic, assign) UInt32 businessType;
/** 网页业务参数
* @attention
*/
@property (nonatomic, strong, nullable) NSDictionary *queryInfoDic;
@end
#pragma mark - WXOpenBusinessWebViewResp
/*! @brief 微信终端向第三方程序返回的WXOpenBusinessWebViewResp处理结果。
*
* 第三方程序向微信终端发送WXOpenBusinessWebViewReq后,微信发送回来的处理结果,该结果用WXOpenBusinessWebViewResp表示。
*/
@interface WXOpenBusinessWebViewResp : BaseResp
/** 第三方程序自定义简单数据,微信终端会回传给第三方程序处理
* @attention 长度不能超过2k
*/
@property (nonatomic, copy) NSString *result;
/** 网页业务类型
* @attention
*/
@property (nonatomic, assign) UInt32 businessType;
@end
#pragma mark - OpenRankListReq
/* ! @brief 第三方通知微信,打开硬件排行榜
*
* 第三方通知微信,打开硬件排行榜
*/
@interface OpenRankListReq : BaseReq
@end
#pragma mark - OpenRanklistResp
/*! @brief 微信终端向第三方程序返回的OpenRankListReq处理结果。
*
* 第三方程序向微信终端发送OpenRankListReq后,微信发送回来的处理结果,该结果用OpenRankListResp表示。
*/
@interface OpenRankListResp : BaseResp
@end
#pragma mark - WXCardItem
@interface WXCardItem : NSObject
/** 卡id
* @attention 长度不能超过1024字节
*/
@property (nonatomic, copy) NSString *cardId;
/** ext信息
* @attention 长度不能超过2024字节
*/
@property (nonatomic, copy, nullable) NSString *extMsg;
/**
* @attention 卡的状态,req不需要填。resp:0为未添加,1为已添加。
*/
@property (nonatomic, assign) UInt32 cardState;
/**
* @attention req不需要填,chooseCard返回的。
*/
@property (nonatomic, copy) NSString *encryptCode;
/**
* @attention req不需要填,chooseCard返回的。
*/
@property (nonatomic, copy) NSString *appID;
@end;
#pragma mark - WXInvoiceItem
@interface WXInvoiceItem : NSObject
/** 卡id
* @attention 长度不能超过1024字节
*/
@property (nonatomic, copy) NSString *cardId;
/** ext信息
* @attention 长度不能超过2024字节
*/
@property (nonatomic, copy, nullable) NSString *extMsg;
/**
* @attention 卡的状态,req不需要填。resp:0为未添加,1为已添加。
*/
@property (nonatomic, assign) UInt32 cardState;
/**
* @attention req不需要填,chooseCard返回的。
*/
@property (nonatomic, copy) NSString *encryptCode;
/**
* @attention req不需要填,chooseCard返回的。
*/
@property (nonatomic, copy) NSString *appID;
@end
#pragma mark - AddCardToWXCardPackageReq
/* ! @brief 请求添加卡券至微信卡包
*
*/
@interface AddCardToWXCardPackageReq : BaseReq
/** 卡列表
* @attention 个数不能超过40个 类型WXCardItem
*/
@property (nonatomic, strong) NSArray *cardAry;
@end
#pragma mark - AddCardToWXCardPackageResp
/** ! @brief 微信返回第三方添加卡券结果
*
*/
@interface AddCardToWXCardPackageResp : BaseResp
/** 卡列表
* @attention 个数不能超过40个 类型WXCardItem
*/
@property (nonatomic, strong) NSArray *cardAry;
@end
#pragma mark - WXChooseCardReq
/* ! @brief 请求从微信选取卡券
*
*/
@interface WXChooseCardReq : BaseReq
@property (nonatomic, copy) NSString *appID;
@property (nonatomic, assign) UInt32 shopID;
@property (nonatomic, assign) UInt32 canMultiSelect;
@property (nonatomic, copy) NSString *cardType;
@property (nonatomic, copy) NSString *cardTpID;
@property (nonatomic, copy) NSString *signType;
@property (nonatomic, copy) NSString *cardSign;
@property (nonatomic, assign) UInt32 timeStamp;
@property (nonatomic, copy) NSString *nonceStr;
@end
#pragma mark - WXChooseCardResp
/** ! @brief 微信返回第三方请求选择卡券结果
*
*/
@interface WXChooseCardResp : BaseResp
@property (nonatomic, strong ) NSArray* cardAry;
@end
#pragma mark - WXChooseInvoiceReq
/* ! @brief 请求从微信选取发票
*
*/
@interface WXChooseInvoiceReq : BaseReq
@property (nonatomic, copy) NSString *appID;
@property (nonatomic, assign) UInt32 shopID;
@property (nonatomic, copy) NSString *signType;
@property (nonatomic, copy) NSString *cardSign;
@property (nonatomic, assign) UInt32 timeStamp;
@property (nonatomic, copy) NSString *nonceStr;
@end
#pragma mark - WXChooseInvoiceResp
/** ! @brief 微信返回第三方请求选择发票结果
*
*/
@interface WXChooseInvoiceResp : BaseResp
@property (nonatomic, strong) NSArray* cardAry;
@end
#pragma mark - WXSubscriptionReq
@interface WXSubscribeMsgReq : BaseReq
@property (nonatomic, assign) UInt32 scene;
@property (nonatomic, copy) NSString *templateId;
@property (nonatomic, copy, nullable) NSString *reserved;
@end
#pragma mark - WXSubscriptionReq
@interface WXSubscribeMsgResp : BaseResp
@property (nonatomic, copy) NSString *templateId;
@property (nonatomic, assign) UInt32 scene;
@property (nonatomic, copy) NSString *action;
@property (nonatomic, copy) NSString *reserved;
@property (nonatomic, copy, nullable) NSString *openId;
@end
#pragma mark - WXSubscribeMiniProgramMsg
/** ! @brief 第三方请求订阅小程序消息
*
*/
@interface WXSubscribeMiniProgramMsgReq : BaseReq
@property (nonatomic, copy) NSString *miniProgramAppid;
@end
#pragma mark - WXSubscriptionReq
@interface WXSubscribeMiniProgramMsgResp : BaseResp
@property(nonatomic, copy) NSString *openId; // 小程序openid
@property(nonatomic, copy) NSString *unionId; // unionId
@property(nonatomic, copy) NSString *nickName; // 用户昵称
@end
#pragma mark - WXinvoiceAuthInsertReq
@interface WXInvoiceAuthInsertReq : BaseReq
@property (nonatomic, copy) NSString *urlString;
@end
#pragma mark - WXinvoiceAuthInsertResp
@interface WXInvoiceAuthInsertResp : BaseResp
@property (nonatomic, copy) NSString *wxOrderId;
@end
#pragma mark - WXMediaMessage
/*! @brief 多媒体消息结构体
*
* 用于微信终端和第三方程序之间传递消息的多媒体消息内容
*/
@interface WXMediaMessage : NSObject
+ (WXMediaMessage *)message;
/** 标题
* @note 长度不能超过512字节
*/
@property (nonatomic, copy) NSString *title;
/** 描述内容
* @note 长度不能超过1K
*/
@property (nonatomic, copy) NSString *description;
/** 缩略图数据
* @note 大小不能超过64K
*/
@property (nonatomic, strong, nullable) NSData *thumbData;
/**
* @note 长度不能超过64字节
*/
@property (nonatomic, copy, nullable) NSString *mediaTagName;
/**
*
*/
@property (nonatomic, copy, nullable) NSString *messageExt;
@property (nonatomic, copy, nullable) NSString *messageAction;
/**
* 多媒体数据对象,可以为WXImageObject,WXMusicObject,WXVideoObject,WXWebpageObject等。
*/
@property (nonatomic, strong) id mediaObject;
/*! @brief 设置消息缩略图的方法
*
* @param image 缩略图
* @note 大小不能超过64K
*/
- (void)setThumbImage:(UIImage *)image;
@end
#pragma mark - WXImageObject
/*! @brief 多媒体消息中包含的图片数据对象
*
* 微信终端和第三方程序之间传递消息中包含的图片数据对象。
* @note imageData成员不能为空
* @see WXMediaMessage
*/
@interface WXImageObject : NSObject
/*! @brief 返回一个WXImageObject对象
*
* @note 返回的WXImageObject对象是自动释放的
*/
+ (WXImageObject *)object;
/** 图片真实数据内容
* @note 大小不能超过25M
*/
@property (nonatomic, strong) NSData *imageData;
@end
#pragma mark - WXMusicObject
/*! @brief 多媒体消息中包含的音乐数据对象
*
* 微信终端和第三方程序之间传递消息中包含的音乐数据对象。
* @note musicUrl和musicLowBandUrl成员不能同时为空。
* @see WXMediaMessage
*/
@interface WXMusicObject : NSObject
/*! @brief 返回一个WXMusicObject对象
*
* @note 返回的WXMusicObject对象是自动释放的
*/
+ (WXMusicObject *)object;
/** 音乐网页的url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *musicUrl;
/** 音乐lowband网页的url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *musicLowBandUrl;
/** 音乐数据url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *musicDataUrl;
/**音乐lowband数据url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *musicLowBandDataUrl;
/**音乐封面图Url
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *songAlbumUrl;
/**歌词信息 LRC格式
* @note 长度不能超过32K
*/
@property (nonatomic, copy, nullable) NSString *songLyric;
@end
#pragma mark - WXMusicVideoObject
@interface WXMusicVideoObject : NSObject
/*! @brief 返回一个WXMusicVideoObject对象
*
* @note 返回的WXMusicVideoObject对象是自动释放的
*/
+ (WXMusicVideoObject *)object;
/** 音乐网页的url地址
* @note 长度不能超过10K,不能为空
*/
@property (nonatomic, copy) NSString *musicUrl;
/** 音乐数据url地址
* @note 长度不能超过10K,不能为空
*/
@property (nonatomic, copy) NSString *musicDataUrl;
/**歌手名
* @note 长度不能超过1k,不能为空
*/
@property (nonatomic, copy) NSString *singerName;
/**
* @note 音乐时长, 单位毫秒
*/
@property (nonatomic, assign) UInt32 duration;
/**歌词信息 LRC格式
* @note 长度不能超过32K
*/
@property (nonatomic, copy) NSString *songLyric;
/**高清封面图
* @note 大小不能超过1M
*/
@property (nonatomic, strong) NSData *hdAlbumThumbData;
/**音乐专辑名称
* @note 长度不能超过1k
*/
@property (nonatomic, copy, nullable) NSString *albumName;
/**音乐流派
* @note 长度不能超过1k
*/
@property (nonatomic, copy, nullable) NSString *musicGenre;
/**发行时间
* @note Unix时间戳,单位为秒
*/
@property (nonatomic, assign) UInt64 issueDate;
/**音乐标识符
* @note 长度不能超过1K,从微信跳回应用时会带上
*/
@property (nonatomic, copy, nullable) NSString *identification;
/**运营H5地址
* @note 选填,建议填写,用户进入歌曲详情页将展示内嵌的运营H5,可展示该歌曲的相关评论、歌曲推荐等内容,不可诱导下载、分享等。
*/
@property (nonatomic, copy, nullable) NSString *musicOperationUrl;
@end
#pragma mark - WXVideoObject
/*! @brief 多媒体消息中包含的视频数据对象
*
* 微信终端和第三方程序之间传递消息中包含的视频数据对象。
* @note videoUrl和videoLowBandUrl不能同时为空。
* @see WXMediaMessage
*/
@interface WXVideoObject : NSObject
/*! @brief 返回一个WXVideoObject对象
*
* @note 返回的WXVideoObject对象是自动释放的
*/
+ (WXVideoObject *)object;
/** 视频网页的url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *videoUrl;
/** 视频lowband网页的url地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *videoLowBandUrl;
@end
#pragma mark - WXWebpageObject
/*! @brief 多媒体消息中包含的网页数据对象
*
* 微信终端和第三方程序之间传递消息中包含的网页数据对象。
* @see WXMediaMessage
*/
@interface WXWebpageObject : NSObject
/*! @brief 返回一个WXWebpageObject对象
*
* @note 返回的WXWebpageObject对象是自动释放的
*/
+ (WXWebpageObject *)object;
/** 网页的url地址
* @note 不能为空且长度不能超过10K
*/
@property (nonatomic, copy) NSString *webpageUrl;
@end
#pragma mark - WXAppExtendObject
/*! @brief 多媒体消息中包含的App扩展数据对象
*
* 第三方程序向微信终端发送包含WXAppExtendObject的多媒体消息,
* 微信需要处理该消息时,会调用该第三方程序来处理多媒体消息内容。
* @note url,extInfo和fileData不能同时为空
* @see WXMediaMessage
*/
@interface WXAppExtendObject : NSObject
/*! @brief 返回一个WXAppExtendObject对象
*
* @note 返回的WXAppExtendObject对象是自动释放的
*/
+ (WXAppExtendObject *)object;
/** 若第三方程序不存在,微信终端会打开该url所指的App下载地址
* @note 长度不能超过10K
*/
@property (nonatomic, copy) NSString *url;
/** 第三方程序自定义简单数据,微信终端会回传给第三方程序处理
* @note 长度不能超过2K
*/
@property (nonatomic, copy, nullable) NSString *extInfo;
/** App文件数据,该数据发送给微信好友,微信好友需要点击后下载数据,微信终端会回传给第三方程序处理
* @note 大小不能超过10M
*/
@property (nonatomic, strong, nullable) NSData *fileData;
@end
#pragma mark - WXEmoticonObject
/*! @brief 多媒体消息中包含的表情数据对象
*
* 微信终端和第三方程序之间传递消息中包含的表情数据对象。
* @see WXMediaMessage
*/
@interface WXEmoticonObject : NSObject
/*! @brief 返回一个WXEmoticonObject对象
*
* @note 返回的WXEmoticonObject对象是自动释放的
*/
+ (WXEmoticonObject *)object;
/** 表情真实数据内容
* @note 大小不能超过10M
*/
@property (nonatomic, strong) NSData *emoticonData;
@end
#pragma mark - WXFileObject
/*! @brief 多媒体消息中包含的文件数据对象
*
* @see WXMediaMessage
*/
@interface WXFileObject : NSObject
/*! @brief 返回一个WXFileObject对象
*
* @note 返回的WXFileObject对象是自动释放的
*/
+ (WXFileObject *)object;
/** 文件后缀名
* @note 长度不超过64字节
*/
@property (nonatomic, copy) NSString *fileExtension;
/** 文件真实数据内容
* @note 大小不能超过10M
*/
@property (nonatomic, strong) NSData *fileData;
@end
#pragma mark - WXLocationObject
/*! @brief 多媒体消息中包含的地理位置数据对象
*
* 微信终端和第三方程序之间传递消息中包含的地理位置数据对象。
* @see WXMediaMessage
*/
@interface WXLocationObject : NSObject
/*! @brief 返回一个WXLocationObject对象
*
* @note 返回的WXLocationObject对象是自动释放的
*/
+ (WXLocationObject *)object;
/** 地理位置信息
* @note 经纬度
*/
@property (nonatomic, assign) double lng; //经度
@property (nonatomic, assign) double lat; //纬度
@end
#pragma mark - WXTextObject
/*! @brief 多媒体消息中包含的文本数据对象
*
* 微信终端和第三方程序之间传递消息中包含的文本数据对象。
* @see WXMediaMessage
*/
@interface WXTextObject : NSObject
/*! @brief 返回一个WXTextObject对象
*
* @note 返回的WXTextObject对象是自动释放的
*/
+ (WXTextObject *)object;
/** 地理位置信息
* @note 文本内容
*/
@property (nonatomic, copy) NSString *contentText;
@end
#pragma mark - WXMiniProgramObject
@interface WXMiniProgramObject : NSObject
/*! @brief WXMiniProgramObject对象
*
* @note 返回的WXMiniProgramObject对象是自动释放的
*/
+ (WXMiniProgramObject *)object;
/** 低版本网页链接
* @attention 长度不能超过1024字节
*/
@property (nonatomic, copy) NSString *webpageUrl;
/** 小程序username */
@property (nonatomic, copy) NSString *userName;
/** 小程序页面的路径
* @attention 不填默认拉起小程序首页
*/
@property (nonatomic, copy, nullable) NSString *path;
/** 小程序新版本的预览图
* @attention 大小不能超过128k
*/
@property (nonatomic, strong, nullable) NSData *hdImageData;
/** 是否使用带 shareTicket 的转发 */
@property (nonatomic, assign) BOOL withShareTicket;
/** 分享小程序的版本
* @attention (正式,开发,体验)
*/
@property (nonatomic, assign) WXMiniProgramType miniProgramType;
/** 是否禁用转发 */
@property (nonatomic, assign) BOOL disableForward;
@property (nonatomic, assign) BOOL isUpdatableMessage;
@property (nonatomic, assign) BOOL isSecretMessage;
/** 业务所需的额外信息 */
@property (nonatomic, strong, nullable) NSDictionary *extraInfoDic;
@end
#pragma mark - WXGameLiveObject
/*! @brief WXGameLiveObject对象
*
* @note 游戏直播消息类型
*/
@interface WXGameLiveObject : NSObject
+ (WXGameLiveObject *)object;
/** 业务所需的额外信息 */
@property (nonatomic, strong, nullable) NSDictionary *extraInfoDic;
@end
#pragma mark - WXLaunchMiniProgramReq
/*! @brief WXLaunchMiniProgramReq对象, 可实现通过sdk拉起微信小程序
*
* @note 返回的WXLaunchMiniProgramReq对象是自动释放的
*/
@interface WXLaunchMiniProgramReq : BaseReq
+ (WXLaunchMiniProgramReq *)object;
/** 小程序username */
@property (nonatomic, copy) NSString *userName;
/** 小程序页面的路径
* @attention 不填默认拉起小程序首页
*/
@property (nonatomic, copy, nullable) NSString *path;
/** 分享小程序的版本
* @attention (正式,开发,体验)
*/
@property (nonatomic, assign) WXMiniProgramType miniProgramType;
/** ext信息
* @attention json格式
*/
@property (nonatomic, copy, nullable) NSString *extMsg;
/** extDic
* @attention 字典,可存放图片等比较大的数据
*/
@property (nonatomic, copy, nullable) NSDictionary *extDic;
@end
#pragma mark - WXLaunchMiniProgramResp
/*! @brief 微信终端向第三方程序返回的WXLaunchMiniProgramReq处理结果。
*
* 第三方程序向微信终端发送WXLaunchMiniProgramReq后,微信发送回来的处理结果,该结果用WXLaunchMiniProgramResp表示。
*/
@interface WXLaunchMiniProgramResp : BaseResp
@property (nonatomic, copy, nullable) NSString *extMsg;
@end
#pragma mark - WXOpenBusinessViewReq
/*! @brief WXOpenBusinessViewReq对象, 可实现第三方通知微信启动,打开业务页面
*
* @note 返回的WXOpenBusinessViewReq对象是自动释放的
*/
@interface WXOpenBusinessViewReq : BaseReq
+ (WXOpenBusinessViewReq *)object;
/** 业务类型
*/
@property (nonatomic, copy) NSString *businessType;
/** 业务参数
*/
@property (nonatomic, copy, nullable) NSString *query;
/** ext信息
* @note 选填,json格式
*/
@property (nonatomic, copy, nullable) NSString *extInfo;
/** extData数据
* @note
*/
@property (nonatomic, strong, nullable) NSData *extData;
@end
@interface WXOpenBusinessViewResp : BaseResp
/** 业务类型
*/
@property (nonatomic, copy) NSString *businessType;
/** 业务返回数据
*/
@property (nonatomic, copy, nullable) NSString *extMsg;
@end
#pragma mark - WXOpenCustomerServiceReq
@interface WXOpenCustomerServiceReq : BaseReq
+ (WXOpenCustomerServiceReq *)object;
/**企微客服发起流程 url
*/
@property (nonatomic, copy, nullable) NSString *url;
/**企业 id
*/
@property (nonatomic, copy, nullable) NSString *corpid;
@end
@interface WXOpenCustomerServiceResp : BaseResp
/** 业务返回数据
*/
@property (nonatomic, copy, nullable) NSString *extMsg;
@end
NS_ASSUME_NONNULL_END
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
#import "WXApiObject.h"
#import "FluwxResponseHandler.h"
NS_ASSUME_NONNULL_BEGIN
@interface WXApiRequestHandler : NSObject
+ (void)sendText:(NSString *)text
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendImageData:(NSData *)imageData
TagName:(NSString *)tagName
MessageExt:(NSString *)messageExt
Action:(NSString *)action
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
title:(NSString *)title
description:(NSString *)description
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendLinkURL:(NSString *)urlString
TagName:(NSString *)tagName
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendMusicURL:(NSString *)musicURL
dataURL:(NSString *)dataURL
MusicLowBandUrl:(NSString *)musicLowBandUrl
MusicLowBandDataUrl:(NSString *)musicLowBandDataUrl
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendVideoURL:(NSString *)videoURL
VideoLowBandUrl:(NSString *)videoLowBandUrl
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendEmotionData:(NSData *)emotionData
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendFileData:(NSData *)fileData
fileExtension:(NSString *)extension
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendMiniProgramWebpageUrl:(NSString *)webpageUrl
userName:(NSString *)userName
path:(NSString *)path
title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
hdImageData:(NSData *)hdImageData
withShareTicket:(BOOL)withShareTicket
miniProgramType:(WXMiniProgramType)programType
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)launchMiniProgramWithUserName:(NSString *)userName
path:(NSString *)path
type:(WXMiniProgramType)miniProgramType
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendAppContentData:(NSData *)data
ExtInfo:(NSString *)info
ExtURL:(NSString *)url
Title:(NSString *)title
Description:(NSString *)description
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)action
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)addCardsToCardPackage:(NSArray *)cardIds cardExts:(NSArray *)cardExts
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendAuthRequestScope:(NSString *)scope
State:(NSString *)state
OpenID:(NSString *)openID
InViewController:(UIViewController *)viewController
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendAuthRequestScope:(NSString *)scope
State:(NSString *)state
OpenID:(NSString *)openID
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)chooseCard:(NSString *)appid
cardSign:(NSString *)cardSign
nonceStr:(NSString *)nonceStr
signType:(NSString *)signType
timestamp:(UInt32)timestamp
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)chooseInvoice:(NSString *)appid
timestamp:(UInt32)timestamp
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)openUrl:(NSString *)url
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)sendPayment:(NSString *)appId
PartnerId:(NSString *)partnerId
PrepayId:(NSString *)prepayId
NonceStr:(NSString *)nonceStr
Timestamp:(UInt32)timestamp
Package:(NSString *)package
Sign:(NSString *)sign
completion:(void (^ __nullable)(BOOL success))completion;
+ (void)openCustomerService:(NSString *)url
CorpId:(NSString *)corpId
completion:(void (^ __nullable)(BOOL success))completion;
@end
NS_ASSUME_NONNULL_END
//
// Created by mo on 2020/3/7.
//
#import "WXApi.h"
#import "WXApiRequestHandler.h"
#import "SendMessageToWXReq+requestWithTextOrMediaMessage.h"
#import "WXMediaMessage+messageConstruct.h"
#import "FluwxStringUtil.h"
#import "WXApiObject.h"
@implementation WXApiRequestHandler
#pragma mark - Public Methods
+ (void)sendText:(NSString *)text
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:text
OrMediaMessage:nil
bText:YES
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendImageData:(NSData *)imageData
TagName:(NSString *)tagName
MessageExt:(NSString *)messageExt
Action:(NSString *)action
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
title:(NSString *)title
description:(NSString *)description
completion:(void (^ __nullable)(BOOL success))completion {
WXImageObject *ext = [WXImageObject object];
ext.imageData = imageData;
WXMediaMessage *message = [WXMediaMessage messageWithTitle:(title == (id) [NSNull null]) ? nil : title
Description:(description == (id) [NSNull null]) ? nil : description
Object:ext
MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt
MessageAction:(action == (id) [NSNull null]) ? nil : action
ThumbImage:thumbImage
MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName];
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendLinkURL:(NSString *)urlString
TagName:(NSString *)tagName
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXWebpageObject *ext = [WXWebpageObject object];
ext.webpageUrl = urlString;
WXMediaMessage *message = [WXMediaMessage messageWithTitle:(title == (id) [NSNull null]) ? nil : title
Description:(description == (id) [NSNull null]) ? nil : description
Object:ext
MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt
MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction
ThumbImage:thumbImage
MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName];
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendMusicURL:(NSString *)musicURL
dataURL:(NSString *)dataURL
MusicLowBandUrl:(NSString *)musicLowBandUrl
MusicLowBandDataUrl:(NSString *)musicLowBandDataUrl
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXMusicObject *ext = [WXMusicObject object];
if ([FluwxStringUtil isBlank:musicURL]) {
ext.musicLowBandUrl = musicLowBandUrl;
ext.musicLowBandDataUrl = (musicLowBandDataUrl == (id) [NSNull null]) ? nil : musicLowBandDataUrl;
} else {
ext.musicUrl = musicURL;
ext.musicDataUrl = (dataURL == (id) [NSNull null]) ? nil : dataURL;
}
WXMediaMessage *message = [WXMediaMessage messageWithTitle:(title == (id) [NSNull null]) ? nil : title
Description:description
Object:ext
MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt
MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction
ThumbImage:thumbImage
MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName];
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendVideoURL:(NSString *)videoURL
VideoLowBandUrl:(NSString *)videoLowBandUrl
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXMediaMessage *message = [WXMediaMessage message];
message.title = (title == (id) [NSNull null]) ? nil : title;
message.description = (description == (id) [NSNull null]) ? nil : description;
message.messageExt = (messageExt == (id) [NSNull null]) ? nil : messageExt;
message.messageAction = (messageAction == (id) [NSNull null]) ? nil : messageAction;
message.mediaTagName = (tagName == (id) [NSNull null]) ? nil : tagName;
[message setThumbImage:thumbImage];
WXVideoObject *ext = [WXVideoObject object];
if ([FluwxStringUtil isBlank:videoURL]) {
ext.videoLowBandUrl = videoLowBandUrl;
} else {
ext.videoUrl = videoURL;
}
message.mediaObject = ext;
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendEmotionData:(NSData *)emotionData
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXMediaMessage *message = [WXMediaMessage message];
[message setThumbImage:thumbImage];
WXEmoticonObject *ext = [WXEmoticonObject object];
ext.emoticonData = emotionData;
message.mediaObject = ext;
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendFileData:(NSData *)fileData
fileExtension:(NSString *)extension
Title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXMediaMessage *message = [WXMediaMessage message];
message.title = title;
message.description = description;
[message setThumbImage:thumbImage];
WXFileObject *ext = [WXFileObject object];
ext.fileExtension = extension;
ext.fileData = fileData;
message.mediaObject = ext;
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)sendMiniProgramWebpageUrl:(NSString *)webpageUrl
userName:(NSString *)userName
path:(NSString *)path
title:(NSString *)title
Description:(NSString *)description
ThumbImage:(UIImage *)thumbImage
hdImageData:(NSData *)hdImageData
withShareTicket:(BOOL)withShareTicket
miniProgramType:(WXMiniProgramType)programType
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)messageAction
TagName:(NSString *)tagName
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXMiniProgramObject *ext = [WXMiniProgramObject object];
ext.webpageUrl = (webpageUrl == (id) [NSNull null]) ? nil : webpageUrl;
ext.userName = (userName == (id) [NSNull null]) ? nil : userName;
ext.path = (path == (id) [NSNull null]) ? nil : path;
ext.hdImageData = (hdImageData == (id) [NSNull null]) ? nil : hdImageData;
ext.withShareTicket = withShareTicket;
// WXMiniProgramType miniProgramType = WXMiniProgramTypeRelease;
// if(programType == 0){
// miniProgramType = WXMiniProgramTypeRelease;
// } else if(programType == 1){
// miniProgramType =WXMiniProgramTypeTest;
// } else if(programType == 2){
// miniProgramType = WXMiniProgramTypePreview;
// }
ext.miniProgramType = programType;
WXMediaMessage *message = [WXMediaMessage messageWithTitle:(title == (id) [NSNull null]) ? nil : title
Description:(description == (id) [NSNull null]) ? nil : description
Object:ext
MessageExt:(messageExt == (id) [NSNull null]) ? nil : messageExt
MessageAction:(messageAction == (id) [NSNull null]) ? nil : messageAction
ThumbImage:thumbImage
MediaTag:(tagName == (id) [NSNull null]) ? nil : tagName];
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)launchMiniProgramWithUserName:(NSString *)userName
path:(NSString *)path
type:(WXMiniProgramType)miniProgramType
completion:(void (^ __nullable)(BOOL success))completion {
WXLaunchMiniProgramReq *launchMiniProgramReq = [WXLaunchMiniProgramReq object];
launchMiniProgramReq.userName = userName;
launchMiniProgramReq.path = (path == (id) [NSNull null]) ? nil : path;
launchMiniProgramReq.miniProgramType = miniProgramType;
[WXApi sendReq:launchMiniProgramReq completion:completion];
}
+ (void)sendAppContentData:(NSData *)data
ExtInfo:(NSString *)info
ExtURL:(NSString *)url
Title:(NSString *)title
Description:(NSString *)description
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)action
ThumbImage:(UIImage *)thumbImage
InScene:(enum WXScene)scene
completion:(void (^ __nullable)(BOOL success))completion {
WXAppExtendObject *ext = [WXAppExtendObject object];
ext.extInfo = info;
ext.url = url;
ext.fileData = data;
WXMediaMessage *message = [WXMediaMessage messageWithTitle:title
Description:description
Object:ext
MessageExt:messageExt
MessageAction:action
ThumbImage:thumbImage
MediaTag:nil];
SendMessageToWXReq *req = [SendMessageToWXReq requestWithText:nil
OrMediaMessage:message
bText:NO
InScene:scene];
[WXApi sendReq:req completion:completion];
}
+ (void)addCardsToCardPackage:(NSArray *)cardIds cardExts:(NSArray *)cardExts
completion:(void (^ __nullable)(BOOL success))completion {
NSMutableArray *cardItems = [NSMutableArray array];
for (NSString *cardId in cardIds) {
WXCardItem *item = [[WXCardItem alloc] init];
item.cardId = cardId;
item.appID = @"wxf8b4f85f3a794e77";
[cardItems addObject:item];
}
for (NSInteger index = 0; index < cardItems.count; index++) {
WXCardItem *item = cardItems[index];
NSString *ext = cardExts[index];
item.extMsg = ext;
}
AddCardToWXCardPackageReq *req = [[AddCardToWXCardPackageReq alloc] init];
req.cardAry = cardItems;
[WXApi sendReq:req completion:completion];
}
+ (void)chooseCard:(NSString *)appid
cardSign:(NSString *)cardSign
nonceStr:(NSString *)nonceStr
signType:(NSString *)signType
timestamp:(UInt32)timestamp
completion:(void (^ __nullable)(BOOL success))completion {
WXChooseCardReq *chooseCardReq = [[WXChooseCardReq alloc] init];
chooseCardReq.appID = appid;
chooseCardReq.cardSign = cardSign;
chooseCardReq.nonceStr = nonceStr;
chooseCardReq.signType = signType;
chooseCardReq.timeStamp = timestamp;
[WXApi sendReq:chooseCardReq completion:completion];
}
+ (void)chooseInvoice:(NSString *)appid
timestamp:(UInt32)timestamp
completion:(void (^ __nullable)(BOOL success))completion {
WXChooseInvoiceReq *chooseInvoiceReq = [[WXChooseInvoiceReq alloc] init];
chooseInvoiceReq.appID = appid;
chooseInvoiceReq.timeStamp = timestamp;
chooseInvoiceReq.signType = @"SHA1";
chooseInvoiceReq.cardSign = @"";
chooseInvoiceReq.nonceStr = @"";
[WXApi sendReq:chooseInvoiceReq completion:completion];
}
+ (void)sendAuthRequestScope:(NSString *)scope
State:(NSString *)state
OpenID:(NSString *)openID
InViewController:(UIViewController *)viewController
completion:(void (^ __nullable)(BOOL success))completion {
SendAuthReq *req = [[SendAuthReq alloc] init];
req.scope = scope; // @"post_timeline,sns"
req.state = state;
req.openID = openID;
return [WXApi sendAuthReq:req
viewController:viewController
delegate:[FluwxResponseHandler defaultManager]
completion:completion];
}
+ (void)sendAuthRequestScope:(NSString *)scope
State:(NSString *)state
OpenID:(NSString *)openID
completion:(void (^ __nullable)(BOOL success))completion {
SendAuthReq *req = [[SendAuthReq alloc] init];
req.scope = scope; // @"post_timeline,sns"
req.state = state;
req.openID = openID;
[WXApi sendReq:req completion:completion];
}
+ (void)openUrl:(NSString *)url
completion:(void (^ __nullable)(BOOL success))completion {
OpenWebviewReq *req = [[OpenWebviewReq alloc] init];
req.url = url;
[WXApi sendReq:req completion:completion];
}
+ (void)chooseInvoice:(NSString *)appid
cardSign:(NSString *)cardSign
nonceStr:(NSString *)nonceStr
signType:(NSString *)signType
timestamp:(UInt32)timestamp
completion:(void (^ __nullable)(BOOL success))completion {
WXChooseInvoiceReq *chooseInvoiceReq = [[WXChooseInvoiceReq alloc] init];
chooseInvoiceReq.appID = appid;
chooseInvoiceReq.cardSign = cardSign;
chooseInvoiceReq.nonceStr = nonceStr;
chooseInvoiceReq.signType = signType;
// chooseCardReq.cardType = @"INVOICE";
chooseInvoiceReq.timeStamp = timestamp;
// chooseCardReq.canMultiSelect = 1;
[WXApi sendReq:chooseInvoiceReq completion:completion];
}
+ (void)openCustomerService:(NSString *)url CorpId:(NSString *)corpId completion:(void (^)(BOOL))completion{
WXOpenCustomerServiceReq *req = [[WXOpenCustomerServiceReq alloc] init];
req.corpid = corpId; //企业ID
req.url = url; //客服URL
[WXApi sendReq:req completion:completion];
}
@end
//
// WXMediaMessage+messageConstruct.h
// SDKSample
//
// Created by Jeason on 15/7/14.
//
//
#import "WXApiObject.h"
@interface WXMediaMessage (messageConstruct)
+ (WXMediaMessage *)messageWithTitle:(NSString *)title
Description:(NSString *)description
Object:(id)mediaObject
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)action
ThumbImage:(UIImage *)thumbImage
MediaTag:(NSString *)tagName;
@end
//
// WXMediaMessage+messageConstruct.m
// SDKSample
//
// Created by Jeason on 15/7/14.
//
//
#import "WXMediaMessage+messageConstruct.h"
@implementation WXMediaMessage (messageConstruct)
+ (WXMediaMessage *)messageWithTitle:(NSString *)title
Description:(NSString *)description
Object:(id)mediaObject
MessageExt:(NSString *)messageExt
MessageAction:(NSString *)action
ThumbImage:(UIImage *)thumbImage
MediaTag:(NSString *)tagName {
WXMediaMessage *message = [WXMediaMessage message];
message.title = title;
message.description = description;
message.mediaObject = mediaObject;
message.messageExt = messageExt;
message.messageAction = action;
message.mediaTagName = tagName;
[message setThumbImage:thumbImage];
return message;
}
@end
//
// WechatAuthSDK.h
// WechatAuthSDK
//
// Created by 李凯 on 13-11-29.
// Copyright (c) 2013年 Tencent. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
enum AuthErrCode {
WechatAuth_Err_Ok = 0, //Auth成功
WechatAuth_Err_NormalErr = -1, //普通错误
WechatAuth_Err_NetworkErr = -2, //网络错误
WechatAuth_Err_GetQrcodeFailed = -3, //获取二维码失败
WechatAuth_Err_Cancel = -4, //用户取消授权
WechatAuth_Err_Timeout = -5, //超时
};
@protocol WechatAuthAPIDelegate<NSObject>
@optional
- (void)onAuthGotQrcode:(UIImage *)image; //得到二维码
- (void)onQrcodeScanned; //二维码被扫描
- (void)onAuthFinish:(int)errCode AuthCode:(nullable NSString *)authCode; //成功登录
@end
@interface WechatAuthSDK : NSObject{
NSString *_sdkVersion;
__weak id<WechatAuthAPIDelegate> _delegate;
}
@property(nonatomic, weak, nullable) id<WechatAuthAPIDelegate> delegate;
@property(nonatomic, readonly) NSString *sdkVersion; //authSDK版本号
/*! @brief 发送登录请求,等待WechatAuthAPIDelegate回调
*
* @param appId 微信开发者ID
* @param nonceStr 一个随机的尽量不重复的字符串,用来使得每次的signature不同
* @param timeStamp 时间戳
* @param scope 应用授权作用域,拥有多个作用域用逗号(,)分隔
* @param signature 签名
* @param schemeData 会在扫码后拼在scheme后
* @return 成功返回YES,失败返回NO
注:该实现只保证同时只有一个Auth在运行,Auth未完成或未Stop再次调用Auth接口时会返回NO。
*/
- (BOOL)Auth:(NSString *)appId
nonceStr:(NSString *)nonceStr
timeStamp:(NSString *)timeStamp
scope:(NSString *)scope
signature:(NSString *)signature
schemeData:(nullable NSString *)schemeData;
/*! @brief 暂停登录请求
*
* @return 成功返回YES,失败返回NO。
*/
- (BOOL)StopAuth;
@end
NS_ASSUME_NONNULL_END
//
// FluwxDelegate.h
// Pods
//
// Created by Mo on 2022/3/6.
//
#import <Foundation/Foundation.h>
@interface FluwxDelegate : NSObject
@property (strong,nonatomic)NSString *extMsg;
+ (instancetype)defaultManager;
- (void)registerWxAPI:(NSString *)appId universalLink:(NSString *)universalLink;
@end
#import <Flutter/Flutter.h>
@interface FluwxPlugin : NSObject<FlutterPlugin>
@end
//
// Created by mo on 2020/3/7.
//
#import <Foundation/Foundation.h>
#import <Flutter/Flutter.h>
@class FluwxStringUtil;
@interface FluwxShareHandler : NSObject
- (instancetype)initWithRegistrar:(NSObject <FlutterPluginRegistrar> *)registrar;
- (void)handleShare:(FlutterMethodCall *)call result:(FlutterResult)result;
@end
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint fluwx.podspec' to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'fluwx_no_pay'
s.version = '0.0.1'
s.summary = 'A new Flutter plugin for Wechat SDK.'
s.description = <<-DESC
A new Flutter plugin for Wechat SDK.
DESC
s.homepage = 'https://github.com/OpenFlutter/fluwx'
s.license = { :file => '../LICENSE' }
s.author = { 'JarvanMo' => 'jarvan.mo@gmail.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/public/*.h'
s.static_framework = true
s.dependency 'Flutter'
# s.dependency 'WechatOpenSDK', '1.8.6.2'
# s.dependency 'OpenWeChatSDK','~> 1.8.3+10'
# s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/Headers/Public/#{s.name}" }
s.frameworks = ["SystemConfiguration", "CoreTelephony","WebKit"]
s.libraries = ["z", "sqlite3.0", "c++"]
s.preserve_paths = 'Lib/*.a'
s.vendored_libraries = "**/*.a"
s.ios.deployment_target = '9.0'
# Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
end
/// Fluwx is a powerful plugin for WeChatSDK.
/// easy to use.
///
/// A open sou;rce project authorized by [OpenFlutter](https://github.com/OpenFlutter).
library fluwx_no_pay;
export 'package:fluwx_no_pay/src/fluwx_iml.dart';
export 'package:fluwx_no_pay/src/response/wechat_response.dart';
export 'package:fluwx_no_pay/src/share/share_models.dart';
export 'package:fluwx_no_pay/src/wechat_enums.dart';
export 'package:fluwx_no_pay/src/wechat_file.dart' hide FileSchema;
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:fluwx_no_pay/src/wechat_enums.dart';
import 'response/wechat_response.dart';
import 'share/share_models.dart';
const Map<Type, String> _shareModelMethodMapper = {
WeChatShareTextModel: 'shareText',
WeChatShareImageModel: 'shareImage',
WeChatShareMusicModel: 'shareMusic',
WeChatShareVideoModel: 'shareVideo',
WeChatShareWebPageModel: 'shareWebPage',
WeChatShareMiniProgramModel: 'shareMiniProgram',
WeChatShareFileModel: 'shareFile',
};
MethodChannel _channel = MethodChannel('com.jarvanmo/fluwx')
..setMethodCallHandler(_methodHandler);
StreamController<BaseWeChatResponse> _weChatResponseEventHandlerController =
StreamController.broadcast();
/// Response answers from WeChat after sharing, payment etc.
Stream<BaseWeChatResponse> get weChatResponseEventHandler =>
_weChatResponseEventHandlerController.stream;
/// [true] if WeChat installed, otherwise [false].
/// Please add WeChat to the white list in order use this method on IOS.
Future<bool> get isWeChatInstalled async {
return await _channel.invokeMethod('isWeChatInstalled');
}
///just open WeChat, noting to do.
Future<bool> openWeChatApp() async {
return await _channel.invokeMethod('openWXApp');
}
/// It's ok if you register multi times.
/// [appId] is not necessary.
/// if [doOnIOS] is true ,fluwx will register WXApi on iOS.
/// if [doOnAndroid] is true, fluwx will register WXApi on Android.
/// [universalLink] is required if you want to register on iOS.
Future<bool> registerWxApi({
required String appId,
bool doOnIOS: true,
bool doOnAndroid: true,
String? universalLink,
}) async {
if (doOnIOS && Platform.isIOS) {
if (universalLink == null ||
universalLink.trim().isEmpty ||
!universalLink.startsWith('https')) {
throw ArgumentError.value(
universalLink,
"You're trying to use illegal universal link, see "
'https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Access_Guide/iOS.html '
'for more detai.l',
);
}
}
return await _channel.invokeMethod('registerApp', {
'appId': appId,
'iOS': doOnIOS,
'android': doOnAndroid,
'universalLink': universalLink
});
}
// Get ext Message
Future<String?> getExtMsg() {
return _channel.invokeMethod('getExtMsg');
}
/// start Log
/// defalult [WXLogLevel.DETAIL]
Future<bool?> startLog({WXLogLevel logLevel = WXLogLevel.DETAIL}) async {
return await _channel.invokeMethod('startLog', {'logLevel': logLevel.toNativeInt()});
}
/// stop log
Future<bool?> stopLog() async {
return await _channel.invokeMethod('stopLog');
}
/// Share your requests to WeChat.
/// This depends on the actual type of [model].
/// see [_shareModelMethodMapper] for detail.
Future<bool> shareToWeChat(WeChatShareBaseModel model) async {
if (_shareModelMethodMapper.containsKey(model.runtimeType)) {
final methodChannel = _shareModelMethodMapper[model.runtimeType];
if (methodChannel == null) {
throw ArgumentError.value(
'${model.runtimeType} method channel not found',
);
}
return await _channel.invokeMethod(methodChannel, model.toMap());
}
return Future.error('no method mapper found[${model.runtimeType}]');
}
/// The WeChat-Login is under Auth-2.0
/// This method login with native WeChat app.
/// For users without WeChat app, please use [authByQRCode] instead
/// This method only supports getting AuthCode,this is first step to login with WeChat
/// Once AuthCode got, you need to request Access_Token
/// For more information please visit:
/// * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419317851&token=
Future<bool> sendWeChatAuth({
required String scope,
String state = 'state',
}) async {
assert(scope.trim().isNotEmpty);
return await _channel.invokeMethod(
'sendAuth',
{'scope': scope, 'state': state},
);
}
/// open mini-program
/// see [WXMiniProgramType]
Future<bool> launchWeChatMiniProgram({
required String username,
String? path,
WXMiniProgramType miniProgramType = WXMiniProgramType.RELEASE,
}) async {
assert(username.trim().isNotEmpty);
return await _channel.invokeMethod('launchMiniProgram', {
'userName': username,
'path': path,
'miniProgramType': miniProgramType.toNativeInt()
});
}
/// request payment with WeChat.
/// Read the official document for more detail.
/// [timeStamp] is int because [timeStamp] will be mapped to Unit32.
Future<bool> payWithWeChat({
required String appId,
required String partnerId,
required String prepayId,
required String packageValue,
required String nonceStr,
required int timeStamp,
required String sign,
String? signType,
String? extData,
}) async {
return await _channel.invokeMethod('payWithFluwx', {
'appId': appId,
'partnerId': partnerId,
'prepayId': prepayId,
'packageValue': packageValue,
'nonceStr': nonceStr,
'timeStamp': timeStamp,
'sign': sign,
'signType': signType,
'extData': extData,
});
}
/// request Hong Kong Wallet payment with WeChat.
/// Read the official document for more detail.
Future<bool> payWithWeChatHongKongWallet({required String prepayId}) async {
return await _channel.invokeMethod('payWithHongKongWallet', {
'prepayId': prepayId,
});
}
/// subscribe WeChat message
Future<bool> subscribeWeChatMsg({
required String appId,
required int scene,
required String templateId,
String? reserved,
}) async {
return await _channel.invokeMethod(
'subscribeMsg',
{
'appId': appId,
'scene': scene,
'templateId': templateId,
'reserved': reserved,
},
);
}
/// please read official docs.
Future<bool> autoDeDuctWeChat({
required String appId,
required String mchId,
required String planId,
required String contractCode,
required String requestSerial,
required String contractDisplayAccount,
required String notifyUrl,
required String version,
required String sign,
required String timestamp,
String returnApp = '3',
int businessType = 12,
}) async {
return await _channel.invokeMethod('autoDeduct', {
'appid': appId,
'mch_id': mchId,
'plan_id': planId,
'contract_code': contractCode,
'request_serial': requestSerial,
'contract_display_account': contractDisplayAccount,
'notify_url': notifyUrl,
'version': version,
'sign': sign,
'timestamp': timestamp,
'return_app': returnApp,
'businessType': businessType
});
}
/// please read * [official docs](https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/papay/chapter3_2.shtml).
Future<bool> autoDeductWeChatV2(
Map<String, String> queryInfo, {
int businessType = 12,
}) async {
return await _channel.invokeMethod(
'autoDeductV2', {'queryInfo': queryInfo, 'businessType': businessType});
}
/// Sometimes WeChat is not installed on users's devices.However we can
/// request a QRCode so that we can get AuthCode by scanning the QRCode
/// All required params must not be null or empty
/// [schemeData] only works on iOS
/// see * https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=215238808828h4XN&token=&lang=zh_CN
Future<bool> authWeChatByQRCode({
required String appId,
required String scope,
required String nonceStr,
required String timeStamp,
required String signature,
String? schemeData,
}) async {
assert(appId.isNotEmpty);
assert(scope.isNotEmpty);
assert(nonceStr.isNotEmpty);
assert(timeStamp.isNotEmpty);
assert(signature.isNotEmpty);
return await _channel.invokeMethod('authByQRCode', {
'appId': appId,
'scope': scope,
'nonceStr': nonceStr,
'timeStamp': timeStamp,
'signature': signature,
'schemeData': schemeData
});
}
/// stop [authWeChatByQRCode]
Future<bool> stopWeChatAuthByQRCode() async {
return await _channel.invokeMethod('stopAuthByQRCode');
}
Future _methodHandler(MethodCall methodCall) {
final response = BaseWeChatResponse.create(
methodCall.method,
methodCall.arguments,
);
_weChatResponseEventHandlerController.add(response);
return Future.value();
}
/// IOS only
Future<bool> authWeChatByPhoneLogin({
required String scope,
String state = 'state',
}) async {
return await _channel.invokeMethod(
'authByPhoneLogin',
{'scope': scope, 'state': state},
);
}
Future<bool> openWeChatCustomerServiceChat(
{required String url, required String corpId}) async {
return await _channel.invokeMethod(
"openWeChatCustomerServiceChat", {"corpId": corpId, "url": url});
}
/// see * https://pay.weixin.qq.com/wiki/doc/apiv3_partner/Offline/apis/chapter6_2_1.shtml
Future<bool> openWeChatBusinessView(
{required String businessType, required String query}) async {
return await _channel.invokeMethod(
"openBusinessView", {"businessType": businessType, "query": query});
}
Future<bool> checkSupportOpenBusinessView() async {
return await _channel.invokeMethod("checkSupportOpenBusinessView");
}
Future<bool> openWeChatInvoice({
required String appId,
required String cardType,
String locationId = "",
String cardId = "",
String canMultiSelect = "1"
}) async {
return await _channel.invokeMethod("openWeChatInvoice", {
"appId":appId,
"cardType":cardType,
"locationId":locationId,
"cardId": cardId,
"canMultiSelect": canMultiSelect
});
}
\ No newline at end of file
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'dart:typed_data';
const String _errCode = "errCode";
const String _errStr = "errStr";
typedef BaseWeChatResponse _WeChatResponseInvoker(Map argument);
Map<String, _WeChatResponseInvoker> _nameAndResponseMapper = {
"onShareResponse": (Map argument) => WeChatShareResponse.fromMap(argument),
"onAuthResponse": (Map argument) => WeChatAuthResponse.fromMap(argument),
"onLaunchMiniProgramResponse": (Map argument) =>
WeChatLaunchMiniProgramResponse.fromMap(argument),
"onPayResponse": (Map argument) => WeChatPaymentResponse.fromMap(argument),
"onSubscribeMsgResp": (Map argument) =>
WeChatSubscribeMsgResponse.fromMap(argument),
"onWXOpenBusinessWebviewResponse": (Map argument) =>
WeChatOpenBusinessWebviewResponse.fromMap(argument),
"onAuthByQRCodeFinished": (Map argument) =>
WeChatAuthByQRCodeFinishedResponse.fromMap(argument),
"onAuthGotQRCode": (Map argument) =>
WeChatAuthGotQRCodeResponse.fromMap(argument),
"onQRCodeScanned": (Map argument) =>
WeChatQRCodeScannedResponse.fromMap(argument),
"onWXShowMessageFromWX": (Map argument) =>
WeChatShowMessageFromWXRequest.fromMap(argument),
"onWXOpenCustomerServiceChatResponse": (Map argument) =>
WeChatOpenCustomerServiceChatResponse.fromMap(argument),
"onOpenBusinessViewResponse": (Map argument) =>
WeChatOpenBusinessViewResponse.fromMap(argument),
"onOpenWechatInvoiceResponse": (Map argument) =>
WeChatOpenInvoiceResponse.fromMap(argument),
};
class BaseWeChatResponse {
final int errCode;
final String? errStr;
bool get isSuccessful => errCode == 0;
BaseWeChatResponse._(this.errCode, this.errStr);
/// create response from response pool
factory BaseWeChatResponse.create(String name, Map argument) {
var result = _nameAndResponseMapper[name];
if (result == null) {
throw ArgumentError("Can't found instance of $name");
}
return result(argument);
}
}
class WeChatOpenInvoiceResponse extends BaseWeChatResponse {
String? cardItemList;
WeChatOpenInvoiceResponse.fromMap(Map map)
: cardItemList = map["cardItemList"],
super._(map[_errCode], map[_errStr]);
}
class WeChatShareResponse extends BaseWeChatResponse {
final int type;
WeChatShareResponse.fromMap(Map map)
: type = map["type"],
super._(map[_errCode], map[_errStr]);
}
class WeChatAuthResponse extends BaseWeChatResponse {
final int type;
final String? country;
final String? lang;
final String? code;
final String? state;
WeChatAuthResponse.fromMap(Map map)
: type = map["type"],
country = map["country"],
lang = map["lang"],
code = map["code"],
state = map["state"],
super._(map[_errCode], map[_errStr]);
@override
bool operator ==(other) {
if (other is WeChatAuthResponse) {
return code == other.code &&
country == other.country &&
lang == other.lang &&
state == other.state;
} else {
return false;
}
}
@override
int get hashCode =>
super.hashCode + errCode.hashCode &
1345 + errStr.hashCode &
15 + (code ?? "").hashCode &
1432;
}
class WeChatLaunchMiniProgramResponse extends BaseWeChatResponse {
final int? type;
final String? extMsg;
WeChatLaunchMiniProgramResponse.fromMap(Map map)
: type = map["type"],
extMsg = map["extMsg"],
super._(map[_errCode], map[_errStr]);
}
class WeChatPaymentResponse extends BaseWeChatResponse {
final int type;
final String? extData;
WeChatPaymentResponse.fromMap(Map map)
: type = map["type"],
extData = map["extData"],
super._(map[_errCode], map[_errStr]);
}
class WeChatOpenCustomerServiceChatResponse extends BaseWeChatResponse {
WeChatOpenCustomerServiceChatResponse.fromMap(Map map)
:super._(map[_errCode], map[_errStr]);
}
class WeChatOpenBusinessViewResponse extends BaseWeChatResponse {
final String? extMsg;
final String? openid;
final String? businessType;
final int? type;
WeChatOpenBusinessViewResponse.fromMap(Map map)
: extMsg = map["extMsg"],
openid = map["openid"],
businessType = map["businessType"],
type = map["type"],
super._(map[_errCode], map[_errStr]);
}
class WeChatSubscribeMsgResponse extends BaseWeChatResponse {
final String? openid;
final String? templateId;
final String? action;
final String? reserved;
final int scene;
WeChatSubscribeMsgResponse.fromMap(Map map)
: openid = map["openid"],
templateId = map["templateId"],
action = map["action"],
reserved = map["reserved"],
scene = map["scene"],
super._(map[_errCode], map[_errStr]);
}
class WeChatOpenBusinessWebviewResponse extends BaseWeChatResponse {
final int? type;
final int errCode;
final int? businessType;
final String resultInfo;
WeChatOpenBusinessWebviewResponse.fromMap(Map map)
: type = map["type"],
errCode = map[_errCode],
businessType = map["businessType"],
resultInfo = map["resultInfo"],
super._(map[_errCode], map[_errStr]);
}
class WeChatAuthByQRCodeFinishedResponse extends BaseWeChatResponse {
final String? authCode;
final AuthByQRCodeErrorCode? qrCodeErrorCode;
WeChatAuthByQRCodeFinishedResponse.fromMap(Map map)
: authCode = map["authCode"],
qrCodeErrorCode = (_authByQRCodeErrorCodes[_errCode] ??
AuthByQRCodeErrorCode.UNKNOWN),
super._(map[_errCode], map[_errStr]);
}
///[qrCode] in memory.
class WeChatAuthGotQRCodeResponse extends BaseWeChatResponse {
final Uint8List? qrCode;
WeChatAuthGotQRCodeResponse.fromMap(Map map)
: qrCode = map["qrCode"],
super._(map[_errCode], map[_errStr]);
}
class WeChatQRCodeScannedResponse extends BaseWeChatResponse {
WeChatQRCodeScannedResponse.fromMap(Map map)
: super._(map[_errCode], map[_errStr]);
}
// 获取微信打开App时携带的参数
class WeChatShowMessageFromWXRequest extends BaseWeChatResponse {
final String? extMsg;
WeChatShowMessageFromWXRequest.fromMap(Map map)
: extMsg = map["extMsg"],
super._(0, '');
}
///WechatAuth_Err_OK(0),
///WechatAuth_Err_NormalErr(-1),
///WechatAuth_Err_NetworkErr(-2),
///WechatAuth_Err_JsonDecodeErr(-3),
///WechatAuth_Err_Cancel(-4),
///WechatAuth_Err_Timeout(-5),
///WechatAuth_Err_Auth_Stopped(-6);
///[AuthByQRCodeErrorCode.JSON_DECODE_ERR] means WechatAuth_Err_GetQrcodeFailed when platform is iOS
///only Android will get [AUTH_STOPPED]
enum AuthByQRCodeErrorCode {
OK,
NORMAL_ERR,
NETWORK_ERR,
JSON_DECODE_ERR,
CANCEL,
TIMEOUT,
AUTH_STOPPED,
UNKNOWN
}
const Map<int, AuthByQRCodeErrorCode> _authByQRCodeErrorCodes = {
0: AuthByQRCodeErrorCode.OK,
-1: AuthByQRCodeErrorCode.NORMAL_ERR,
-2: AuthByQRCodeErrorCode.NETWORK_ERR,
-3: AuthByQRCodeErrorCode.JSON_DECODE_ERR,
-4: AuthByQRCodeErrorCode.CANCEL,
-5: AuthByQRCodeErrorCode.AUTH_STOPPED
};
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter/foundation.dart';
import 'package:fluwx_no_pay/src/wechat_enums.dart';
import '../wechat_file.dart';
const String _scene = "scene";
const String _source = "source";
const String _thumbnail = "thumbnail";
const String _title = "title";
const String _description = "description";
const String _messageExt = "messageExt";
const String _mediaTagName = "mediaTagName ";
const String _messageAction = "messageAction";
const String _compressThumbnail = "compressThumbnail";
mixin WeChatShareBaseModel {
Map toMap();
}
///[source] the text you want to send to WeChat
///[scene] the target you want to send
class WeChatShareTextModel implements WeChatShareBaseModel {
final String source;
final WeChatScene scene;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final String? title;
final String? description;
WeChatShareTextModel(this.source,
{this.scene = WeChatScene.SESSION,
this.mediaTagName,
this.messageAction,
this.messageExt,
String? description,
String? title})
: this.title = title ?? source,
this.description = description ?? source;
@override
Map toMap() {
return {
_scene: scene.index,
_source: source,
_messageExt: messageExt,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_title: title,
_description: description
};
}
}
///
/// the default value is [MINI_PROGRAM_TYPE_RELEASE]
///[hdImagePath] only works on iOS, not sure the relationship between [thumbnail] and [hdImagePath].
class WeChatShareMiniProgramModel implements WeChatShareBaseModel {
final String webPageUrl;
final WXMiniProgramType miniProgramType;
final String userName;
final String path;
final WeChatImage? hdImagePath;
final String? title;
final String? description;
final WeChatImage? thumbnail;
final bool withShareTicket;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareMiniProgramModel(
{required this.webPageUrl,
this.miniProgramType = WXMiniProgramType.RELEASE,
required this.userName,
this.path: "/",
this.title,
this.description,
this.withShareTicket: false,
this.thumbnail,
this.hdImagePath,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.compressThumbnail = true})
: assert(webPageUrl.isNotEmpty),
assert(userName.isNotEmpty),
assert(path.isNotEmpty);
@override
Map toMap() {
return {
'webPageUrl': webPageUrl,
"miniProgramType": miniProgramType.toNativeInt(),
"userName": userName,
"path": path,
"title": title,
_description: description,
"withShareTicket": withShareTicket,
_thumbnail: thumbnail?.toMap(),
"hdImagePath": hdImagePath?.toMap(),
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_compressThumbnail: compressThumbnail
};
}
}
///[source] the image you want to send to WeChat
///[scene] the target you want to send
///[thumbnail] the preview of your image, will be created from [scene] if null.
class WeChatShareImageModel implements WeChatShareBaseModel {
final WeChatImage source;
final WeChatImage thumbnail;
final String? title;
final WeChatScene scene;
final String? description;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareImageModel(this.source,
{WeChatImage? thumbnail,
this.title,
this.scene = WeChatScene.SESSION,
this.description,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.compressThumbnail = true})
: this.thumbnail = thumbnail ?? source;
@override
Map toMap() {
return {
_scene: scene.index,
_source: source.toMap(),
_thumbnail: thumbnail.toMap(),
_title: title,
_description: description,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_compressThumbnail: compressThumbnail
};
}
}
/// if [musicUrl] and [musicLowBandUrl] are both provided,
/// only [musicUrl] will be used.
class WeChatShareMusicModel implements WeChatShareBaseModel {
final String? musicUrl;
final String? musicDataUrl;
final String? musicLowBandUrl;
final String? musicLowBandDataUrl;
final WeChatImage? thumbnail;
final String? title;
final String? description;
final WeChatScene scene;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareMusicModel(
{this.musicUrl,
this.musicLowBandUrl,
this.title: "",
this.description: "",
this.musicDataUrl,
this.musicLowBandDataUrl,
this.thumbnail,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.scene = WeChatScene.SESSION,
this.compressThumbnail = true})
: assert(musicUrl != null || musicLowBandUrl != null);
@override
Map toMap() {
return {
_scene: scene.index,
"musicUrl": musicUrl,
"musicDataUrl": musicDataUrl,
"musicLowBandUrl": musicLowBandUrl,
"musicLowBandDataUrl": musicLowBandDataUrl,
_thumbnail: thumbnail?.toMap(),
_title: title,
_description: description,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_compressThumbnail: compressThumbnail
};
}
}
/// if [videoUrl] and [videoLowBandUrl] are both provided,
/// only [videoUrl] will be used.
class WeChatShareVideoModel implements WeChatShareBaseModel {
final String? videoUrl;
final String? videoLowBandUrl;
final WeChatImage? thumbnail;
final String? title;
final String? description;
final WeChatScene scene;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareVideoModel(
{this.scene = WeChatScene.SESSION,
this.videoUrl,
this.videoLowBandUrl,
this.title: "",
this.description: "",
this.thumbnail,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.compressThumbnail = true})
: assert(videoUrl != null || videoLowBandUrl != null),
assert(thumbnail != null);
@override
Map toMap() {
return {
_scene: scene.index,
"videoUrl": videoUrl,
"videoLowBandUrl": videoLowBandUrl,
_thumbnail: thumbnail?.toMap(),
_title: title,
_description: description,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_compressThumbnail: compressThumbnail
};
}
}
///[webPage] url you want to send to wechat
///[thumbnail] logo of your website
class WeChatShareWebPageModel implements WeChatShareBaseModel {
final String webPage;
final WeChatImage? thumbnail;
final String title;
final String description;
final WeChatScene scene;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareWebPageModel(this.webPage,
{this.title: "",
String? description,
this.thumbnail,
this.scene = WeChatScene.SESSION,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.compressThumbnail = true})
: assert(webPage.isNotEmpty),
this.description = description ?? webPage;
@override
Map toMap() {
return {
_scene: scene.index,
"webPage": webPage,
_thumbnail: thumbnail?.toMap(),
_title: title,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_description: description,
_compressThumbnail: compressThumbnail
};
}
}
/// [source] the file you want to share, [source.suffix] is necessary on iOS.
/// [scene] can't be [WeChatScene.TIMELINE], otherwise, sharing nothing.
/// send files to WeChat
class WeChatShareFileModel implements WeChatShareBaseModel {
final WeChatFile source;
final WeChatImage? thumbnail;
final String title;
final String description;
final WeChatScene scene;
final String? messageExt;
final String? messageAction;
final String? mediaTagName;
final bool compressThumbnail;
WeChatShareFileModel(this.source,
{this.title: "",
this.description: "",
this.thumbnail,
this.scene = WeChatScene.SESSION,
this.mediaTagName,
this.messageAction,
this.messageExt,
this.compressThumbnail = true});
@override
Map toMap() {
return {
_scene: scene.index,
_source: source.toMap(),
_thumbnail: thumbnail?.toMap(),
_title: title,
_description: description,
_messageAction: messageAction,
_mediaTagName: mediaTagName,
_compressThumbnail: compressThumbnail
};
}
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
///[WXMiniProgramType.RELEASE]正式版
///[WXMiniProgramType.TEST]测试版
///[WXMiniProgramType.PREVIEW]预览版
enum WXMiniProgramType { RELEASE, TEST, PREVIEW }
///[WeChatScene.SESSION]会话
///[WeChatScene.TIMELINE]朋友圈
///[WeChatScene.FAVORITE]收藏
enum WeChatScene { SESSION, TIMELINE, FAVORITE }
extension MiniProgramTypeExtensions on WXMiniProgramType {
int toNativeInt() {
switch (this) {
case WXMiniProgramType.PREVIEW:
return 2;
case WXMiniProgramType.TEST:
return 1;
case WXMiniProgramType.RELEASE:
return 0;
}
return 0;
}
}
/// 打印日常的日志
/// 打印详细的日志
enum WXLogLevel { NORMAL, DETAIL }
extension LogLevelExtensions on WXLogLevel {
int toNativeInt() {
switch (this) {
case WXLogLevel.DETAIL:
return 1;
case WXLogLevel.NORMAL:
return 0;
default:
return 0;
}
}
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'dart:io';
import 'dart:typed_data';
const String defaultSuffixJpeg = ".jpeg";
const String defaultSuffixTxt = ".txt";
class WeChatImage extends WeChatFile {
WeChatImage.network(String source, {String suffix = defaultSuffixJpeg})
: super.network(source, suffix: suffix);
WeChatImage.asset(String source, {String suffix = defaultSuffixJpeg})
: super.asset(source, suffix: suffix);
WeChatImage.file(File source, {String suffix = defaultSuffixJpeg})
: super.file(source, suffix: suffix);
WeChatImage.binary(Uint8List source, {String suffix = defaultSuffixJpeg})
: super.binary(source, suffix: suffix);
}
class WeChatFile {
final dynamic source;
final FileSchema schema;
final String suffix;
/// [source] must begin with http or https
WeChatFile.network(String source, {String? suffix})
: assert(source.startsWith("http")),
this.source = source,
this.schema = FileSchema.NETWORK,
this.suffix = source.readSuffix(suffix, defaultSuffixTxt);
///[source] path of the image, like '/asset/image.pdf?package=flutter',
///the query param package in [source] only available when you want to specify the package of image
WeChatFile.asset(String source, {String? suffix})
: assert(source.trim().isNotEmpty),
this.source = source,
this.schema = FileSchema.ASSET,
this.suffix = source.readSuffix(suffix, defaultSuffixTxt);
WeChatFile.file(File source, {String suffix = defaultSuffixTxt})
: this.source = source.path,
this.schema = FileSchema.FILE,
this.suffix = source.path.readSuffix(suffix, defaultSuffixTxt);
WeChatFile.binary(Uint8List source, {String suffix = defaultSuffixTxt})
: assert(suffix.trim().isNotEmpty),
this.source = source,
this.schema = FileSchema.BINARY,
this.suffix = suffix;
Map toMap() =>
{"source": source, "schema": schema.index, "suffix": suffix};
}
///Types of image, usually there are for types listed below.
///[FileSchema.NETWORK] is online images.
///[FileSchema.ASSET] is flutter asset image.
///[FileSchema.BINARY] is binary image, shall be be [Uint8List]
///[FileSchema.FILE] is local file, usually not comes from flutter asset.
enum FileSchema {
NETWORK,
ASSET,
FILE,
BINARY,
}
extension _FileSuffix on String {
/// returns [suffix] if [suffix] not blank.
/// If [suffix] is blank, then try to read from url
/// if suffix in url not found, then return jpg as default.
String readSuffix(String? suffix, String defaultSuffix) {
if (suffix != null && suffix.trim().isNotEmpty) {
if (suffix.startsWith(".")) {
return suffix;
} else {
return ".$suffix";
}
}
var path = Uri.parse(this).path;
var index = path.lastIndexOf(".");
if (index >= 0) {
return path.substring(index);
}
return defaultSuffix;
}
}
name: fluwx_no_pay
description: The capability of implementing WeChat SDKs in Flutter. With Fluwx, developers can use WeChatSDK easily, such as sharing, payment, lanuch mini program and etc.
version: 3.9.0
homepage: https://github.com/JarvanMo/fluwx
environment:
sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.12.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# This section identifies this Flutter project as a plugin project.
# The androidPackage and pluginClass identifiers should not ordinarily
# be modified. They are used by the tooling to maintain consistency when
# adding or updating assets for this project.
plugin:
platforms:
android:
package: com.jarvan.fluwx
pluginClass: FluwxPlugin
ios:
pluginClass: FluwxPlugin
# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart' as fluwx;
void main() {
const MethodChannel channel = MethodChannel('com.jarvanmo/fluwx');
TestWidgetsFlutterBinding.ensureInitialized();
setUp(() {
channel.setMockMethodCallHandler((MethodCall methodCall) async {
if (methodCall.method == "registerApp") {
if (methodCall.arguments["appId"] == "wx13124324324") {
return Future.value(true);
} else {
return Future.value(false);
}
} else if (methodCall.method == "shareText") {
channel.invokeMethod(
"onShareResponse", {"type": 1, "errCode": 1, "errStr": "hehe"});
return Future.value(true);
} else if (methodCall.method == "shareImage") {
channel.invokeMethod(
"onShareResponse", {"type": 1, "errCode": 0, "errStr": ""});
return Future.value(true);
}
return '42';
});
});
tearDown(() {
channel.setMockMethodCallHandler(null);
});
group("register", () {
test("success", () async {
expect(await fluwx.registerWxApi(appId: "wx13124324324"), true);
});
test("failed", () async {
expect(await fluwx.registerWxApi(appId: "wx131256"), false);
});
});
group("share", () {
test("text", () async {
expect(
await fluwx.shareToWeChat(fluwx.WeChatShareTextModel("text")), true);
});
test("shareImage", () async {
expect(
await fluwx.shareToWeChat(fluwx.WeChatShareImageModel(
fluwx.WeChatImage.network("http://flutter.dev"))),
true);
});
});
group("learn", () {
test("description", () async {
print("argumentsss");
});
});
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart';
void main() {
group("create response", () {
test("WeChatShareResponse", () {
var response = BaseWeChatResponse.create(
"onShareResponse", {"type": 1, "errCode": 1, "errStr": "hehe"});
expect(response is WeChatShareResponse, true);
var casted = response as WeChatShareResponse;
expect(casted.type, 1);
expect(casted.errCode, 1);
expect(casted.errStr, "hehe");
});
test("WeChatAuthResponse", () {
var response = BaseWeChatResponse.create("onAuthResponse", {
"type": 1,
"errCode": 1,
"errStr": "hehe",
"country": "cn",
"lang": "lang",
"code": "code",
"state": "ok"
});
expect(response is WeChatAuthResponse, true);
var casted = response as WeChatAuthResponse;
expect(casted.type, 1);
expect(casted.errCode, 1);
expect(casted.errStr, "hehe");
expect(casted.country, "cn");
expect(casted.lang, "lang");
expect(casted.code, "code");
expect(casted.state, "ok");
});
test("onLaunchMiniProgramResponse", () {
var response = BaseWeChatResponse.create("onLaunchMiniProgramResponse",
{"type": 1, "errCode": 1, "errStr": "hehe", "extMsg": "extMsg"});
expect(response is WeChatLaunchMiniProgramResponse, true);
var casted = response as WeChatLaunchMiniProgramResponse;
expect(casted.type, 1);
expect(casted.errCode, 1);
expect(casted.errStr, "hehe");
expect(casted.extMsg, "extMsg");
});
test("WeChatPaymentResponse", () {
var response = BaseWeChatResponse.create("onPayResponse",
{"type": 1, "errCode": 1, "errStr": "hehe", "extData": "extData"});
expect(response is WeChatPaymentResponse, true);
var casted = response as WeChatPaymentResponse;
expect(casted.type, 1);
expect(casted.errCode, 1);
expect(casted.errStr, "hehe");
expect(casted.extData, "extData");
});
test("WeChatSubscribeMsgResponse", () {
var response = BaseWeChatResponse.create("onSubscribeMsgResp", {
"type": 1,
"errCode": 1,
"errStr": "hehe",
"openid": "425235131",
"templateId": "4252345",
"action": "action",
"reserved": "reserved",
"scene": 1
});
expect(response is WeChatSubscribeMsgResponse, true);
var casted = response as WeChatSubscribeMsgResponse;
expect(casted.errCode, 1);
expect(casted.errStr, "hehe");
expect(casted.openid, "425235131");
expect(casted.templateId, "4252345");
expect(casted.action, "action");
expect(casted.reserved, "reserved");
expect(casted.scene, 1);
});
test("WeChatAutoDeductResponse", () {
var response = BaseWeChatResponse.create("onAutoDeductResponse", {
"type": 1,
"errCode": 0,
"errStr": "hehe",
"businessType": 2,
"resultInfo": "resultInfo"
});
expect(response is WeChatOpenBusinessWebviewResponse, true);
var casted = response as WeChatOpenBusinessWebviewResponse;
assert(casted.isSuccessful);
expect(casted.type, 1);
expect(casted.errCode, 0);
expect(casted.errStr, "hehe");
expect(casted.resultInfo, "resultInfo");
expect(casted.businessType, 2);
});
});
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart';
import 'package:fluwx_no_pay/src/share/share_models.dart';
import 'package:fluwx_no_pay/src/wechat_enums.dart';
void main() {
test("test create WeChatShareImageModel with thumbnail", () {
var image = WeChatImage.network("http://openflutter.dev/fluwx.png");
var thumbnail = WeChatImage.network("http://openflutter.dev/fluwx.png");
var model = WeChatShareImageModel(image,
scene: WeChatScene.FAVORITE, thumbnail: thumbnail);
expect(model.source, image);
expect(model.scene, WeChatScene.FAVORITE);
expect(model.thumbnail, thumbnail);
});
test("test create WeChatShareImageModel without thumbnail", () {
var image = WeChatImage.network("http://openflutter.dev/fluwx.png");
var model = WeChatShareImageModel(image, scene: WeChatScene.FAVORITE);
expect(model.source, image);
expect(model.scene, WeChatScene.FAVORITE);
expect(model.thumbnail, image);
});
test("test WeChatShareImageModel toMap", () {
var image = WeChatImage.network("http://openflutter.dev/fluwx.png");
var thumbnail = WeChatImage.network("http://openflutter.dev/fluwx.png");
var map = WeChatShareImageModel(image,
scene: WeChatScene.FAVORITE, thumbnail: thumbnail)
.toMap();
assert(map["thumbnail"] != null);
expect(map["thumbnail"]["source"], "http://openflutter.dev/fluwx.png");
});
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/src/share/share_models.dart';
import 'package:fluwx_no_pay/src/wechat_enums.dart';
import 'package:fluwx_no_pay/src/wechat_file.dart';
void main() {
group("construct", () {
test("non default values", () {
var thumbnail =
WeChatImage.network("http://openflutter.dev/fluwx.png");
var model = WeChatShareMiniProgramModel(
webPageUrl: "http://openflutter.dev",
miniProgramType: WXMiniProgramType.PREVIEW,
withShareTicket: true,
thumbnail: thumbnail,
userName: "userName",
path: "path",
hdImagePath: thumbnail);
expect(model.webPageUrl, "http://openflutter.dev");
expect(model.miniProgramType, WXMiniProgramType.PREVIEW);
expect(model.thumbnail, thumbnail);
expect(model.hdImagePath, thumbnail);
expect(model.path, "path");
expect(model.userName, "userName");
});
test("default values", () {
var model = WeChatShareMiniProgramModel(
webPageUrl: "http://openflutter.dev", userName: "userName");
expect(model.webPageUrl, "http://openflutter.dev");
expect(model.miniProgramType, WXMiniProgramType.RELEASE);
expect(model.thumbnail, null);
expect(model.path, "/");
expect(model.userName, "userName");
});
});
group("toMap", () {
test("with thumbnail", () {
var thumbnail =
WeChatImage.network("http://openflutter.dev/fluwx.png");
var map = WeChatShareMiniProgramModel(
webPageUrl: "http://openflutter.dev",
miniProgramType: WXMiniProgramType.PREVIEW,
withShareTicket: true,
thumbnail: thumbnail,
userName: "userName",
path: "path")
.toMap();
expect(map["webPageUrl"], "http://openflutter.dev");
expect(map["miniProgramType"], 2);
expect(map["thumbnail"]["source"], "http://openflutter.dev/fluwx.png");
expect(map["path"], "path");
expect(map["userName"], "userName");
});
test("without thumbnail", () {
var map = WeChatShareMiniProgramModel(
webPageUrl: "http://openflutter.dev",
miniProgramType: WXMiniProgramType.PREVIEW,
withShareTicket: true,
userName: "userName",
path: "path")
.toMap();
expect(map["webPageUrl"], "http://openflutter.dev");
expect(map["miniProgramType"], 2);
expect(map["thumbnail"], null);
expect(map["path"], "path");
expect(map["userName"], "userName");
});
});
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/src/share/share_models.dart';
import 'package:fluwx_no_pay/src/wechat_enums.dart';
void main() {
test("create WeChatTextModel", () {
var model = WeChatShareTextModel("text", scene: WeChatScene.FAVORITE);
expect(model.source, "text");
expect(model.scene, WeChatScene.FAVORITE);
});
test("WeChatTextModel toMap", () {
var map = WeChatShareTextModel("text", scene: WeChatScene.FAVORITE).toMap();
expect(map["source"], "text");
expect(map["scene"], 2);
});
}
/*
* Copyright (c) 2020. OpenFlutter Project
*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. The ASF licenses this
* file to you under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx_no_pay/fluwx_no_pay.dart';
import 'package:fluwx_no_pay/src/wechat_file.dart';
void main() {
test("test WeChatImage.fromNetwork", () {
var withSuffixImage =
WeChatImage.network("http://image.openflutter.dev/fluwx.png");
expect(withSuffixImage.source, "http://image.openflutter.dev/fluwx.png");
expect(withSuffixImage.suffix, ".png");
expect(FileSchema.NETWORK, withSuffixImage.schema);
var withNoSuffixNoUrlSuffixImage =
WeChatImage.network("http://image.openflutter.dev/fluwx");
expect("http://image.openflutter.dev/fluwx",
withNoSuffixNoUrlSuffixImage.source);
expect(withNoSuffixNoUrlSuffixImage.suffix, ".jpeg");
expect(FileSchema.NETWORK, withSuffixImage.schema);
var withSpecifiedSuffixImage = WeChatImage.network(
"http://image.openflutter.dev/fluwx.jpeg",
suffix: ".png");
expect(withSpecifiedSuffixImage.source, "http://image.openflutter.dev/fluwx.jpeg");
expect(withSpecifiedSuffixImage.suffix, ".png");
expect(withSpecifiedSuffixImage.schema, FileSchema.NETWORK);
});
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论