Unverified 提交 a696b70c authored 作者: JarvanMo's avatar JarvanMo 提交者: GitHub

Merge pull request #195 from OpenFlutter/v2.0

V2.0
......@@ -8,14 +8,14 @@ task:
setup_script:
- flutter channel stable
- flutter upgrade
build_script:
build_script:
- cd example
- flutter build apk
#test_script: flutter test
task:
osx_instance:
image: mojave-flutter
image: mojave-xcode-11.3-flutter
pub_cache:
folder: ~/.pub-cache
setup_script:
......@@ -24,8 +24,8 @@ task:
- flutter upgrade
create_simulator_script:
- xcrun simctl list
- xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-2 | xargs xcrun simctl boot
build_script:
- xcrun simctl create Flutter-iPhone com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-13-3 | xargs xcrun simctl boot
build_script:
- cd example
- flutter build ios --no-codesign
#test_script: flutter test
*.dart linguist-language=Dart
*.m linguist-language=Dart
*.h linguist-language=Dart
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Flutter Version:**
Run `flutter doctor` in terminal or powershell , and copy the outputs.
**Testing Platform:**
Android or iOS?
**Additional context**
Add any other context about the problem here.
#Sat Mar 07 20:06:05 CST 2020
gradle.version=5.2.1
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
channel: stable
project_type: plugin
## 2.0.0
* 代码重构,现在代码结构更清晰
* 所有图片由WeChatImage构建
* 现在iOS对分享微信小程序的高清图也会压缩
* 微信回调监听形式变更
* Android增加新的Action以防微信打开小程序出错不会返回原app的问题
* iOS改用Pod引用微信SDK
* iOS隐藏一些header
## 1.2.1+2
* iOS的StringUtil重命名了
......
差异被折叠。
# Fluwx
# Fluwx
![pub package](https://img.shields.io/pub/v/fluwx.svg)
[![Build status](https://img.shields.io/cirrus/github/OpenFlutter/fluwx/master)](https://cirrus-ci.com/github/OpenFlutter/fluwx)
======
![logo](./arts/fluwx_logo.png)
![logo](https://github.com/JarvanMo/ImagesStore/blob/master/fluwx/fluwx_logo.png)
[中文请移步此处](./README_CN.md)
`Fluwx` makes easier using WeChatSDK on Flutter.
QQ Group:892398530。
## 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.
# V2.0 is coming. Broken changes!!!
> Join QQ Group now: 892398530。
## Before
Before using`Fluwx`,read [the official documents](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1) first.
This is very important because some configurations or details are not listed here.
## 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.
## Preparation
### What does Fluwx support?
* Share Text.
* Share WebPage.
* Share Image.
* Share Music.
* Share Video.
* Share MiniProgram.
* Send Auth(Login).
* Pay.
* Launch Mini-Program.
* Subscribe Message.
* Auth By QRCode.
* Sign Auto-Deduct.
* Open WeChat App.
`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.
## Sample
[Watch Charged Video](https://study.163.com/course/introduction.htm?share=2&shareId=480000001896427&courseId=1209174838&_trace_c_p_k2_=e72467dc0df540579287a8ea996344a4)
[See sample here](./example)
[watch charged video here](https://study.163.com/course/introduction.htm?share=2&shareId=480000001896427&courseId=1209174838&_trace_c_p_k2_=e72467dc0df540579287a8ea996344a4)
[upgrade to 1.0.0 or above](./doc/QUESTIONS.md)
## Dependencies
## 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)
> Latest version is ![pub package](https://img.shields.io/pub/v/fluwx.svg)
For using the snapshot:
`Fluwx` without pay:
```yaml
dependencies:
fluwx:
git:
url: https://github.com/OpenFlutter/fluwx
fluwx_no_pay: ^${latestVersion}
```
please check *no_pay* branch for no pay-sdk support.
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)
## Register WeChatSDK via Fluwx
> NOTE: Never forget to replace ^${latestVersion} with actual version.
Before using`Fluwx`,you should init `FLuwx`
## Register WxAPI
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.registerWxApi(appId:"wxd930ea5d5a258f4f",universalLink:"https://your.univeral.link.com/placeholder/");
```
Developers must provide `universalLink` if you want register WeChat via fluwx, otherwise, ignore. Incorrect `universalLink` won't pass the register of SDK.
Register your app via `fluwx` if necessary.
```dart
registerWxApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/");
```
> NOTE:Although we can register WXApi via Fluwx,but there's still some work you have to do on the particular platform.For example, add *URLSchema, LSApplicationQueriesSchemes or universal link* for iOS.
Please read the official documents for details.
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.
### More
* [Share](./doc/SHARE.md)
* [Auth](./doc/SEND_AUTH.md)
* [Payment](./doc/WXPay.md)
* [Launch Mini-Program](./doc/LAUNCH_MINI_PROGRAM.md)
* [Subscribe Message](./doc/SUBSCRIBE_MESSAGE.md)
* [Auth By QRCode](./doc/AUTH_BY_QR_CODE.md)
* [Sign Auto-Deduct](./doc/AUTO_DEDUCT.md)
* [Receive Response Or Callback From WeChat](./doc/RESPONSE.md)
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`.
### Other
* [Having Questions?](./doc/QUESTIONS.md)
## Capability Document
### Waiting
- [Basic knowledge](./docs/BASIC_KNOWLEDGE.md)
- [Share](./docs/SHARE.md)
- [Payment](./dosc/PAYMENT.md)
- [Auth](./docs/AUTH.md)
For more capabilities, you can read the public functions of `fluwx`.
### Donate
Buy the writer a cup of coffee。
<img src="./arts/wx.jpeg" height="300"> <img src="./arts/ali.jpeg" height="300">
<img src="https://github.com/JarvanMo/ImagesStore/blob/master/common/wx.jpeg" height="300"> <img src="https://github.com/JarvanMo/ImagesStore/blob/master/common/ali.jpeg" height="300">
### Subscribe Us On WeChat
![subscribe](./arts/wx_subscription.png)
![subscribe](https://github.com/JarvanMo/ImagesStore/blob/master/fluwx/wx_subscription.png)
## LICENSE
......@@ -120,3 +102,8 @@ Buy the writer a cup of coffee。
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
# Fluwx
![pub package](https://img.shields.io/pub/v/fluwx.svg)
[![Build status](https://img.shields.io/cirrus/github/OpenFlutter/fluwx/master)](https://cirrus-ci.com/github/OpenFlutter/fluwx)
======
![logo](./arts/fluwx_logo.png)
![logo](https://github.com/JarvanMo/ImagesStore/blob/master/fluwx/fluwx_logo.png)
适用于Flutter的微信SDK,方便快捷。
QQ群:892398530。
## 什么是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).
# V2.0 正在开发. 破坏性更新!!!
> Join QQ Group now: 892398530。
## 使用需知
使用`Fluwx`之前,强烈建议先阅读[微信SDK官方文档](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1)
这有助于你使用`Fluwx`
这很重要,因为有一些概念以及配置不会体现在本文档中。
## 能力
### 目前功能
* 文本分享。
* 网站分享。
* 图片分享。
* 音乐分享。
* 视频分享。
* 小程序分享。
* 发送Auth认证(登录)。
* 支付。
* 打开小程序。
* 一次性订阅消息。
* 二维码登录。
* 签约免密支付。
* 打开微信。
- 分享图片,文本,音乐,视频等。支持分享到会话,朋友圈以及收藏.
- 微信支付.
- 在微信登录时,获取Auth Code.
- 拉起小程序.
- 订阅消息.
- 打开微信.
## 示例
## 准备
[点此查看示例](./example)
`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)
> [收费视频教程点这里](https://study.163.com/course/introduction.htm?share=2&shareId=480000001896427&courseId=1209174838&_trace_c_p_k2_=e72467dc0df540579287a8ea996344a4)
>
## 安装
[升级到1.0.0或者更高](./doc/QUESTIONS_CN.md)
`pubspec.yaml` 文件中添加`fluwx`依赖:
## 引入
在你的 `pubspec.yaml` 文件中添加如下依赖:
`Fluwx`,带支付:
```yaml
dependencies:
fluwx: ^${latestVersion}
```
切换到*no_pay*分支以使用没有支付sdk的fluwx.
> 最新版本为 ![pub package](https://img.shields.io/pub/v/fluwx.svg)
![pub package](https://img.shields.io/pub/v/fluwx.svg)
如果想用github上最新版本:
`Fluwx`,不带支付:
```yaml
dependencies:
fluwx:
git:
url: https://github.com/OpenFlutter/fluwx
fluwx_no_pay: ^${latestVersion}
```
## 初始化
使用`Fluwx`前,需要进行初始化操作:
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.registerWxApi(appId:"wxd930ea5d5a258f4f",universalLink:"https://your.univeral.link.com/placeholder/");
```
如果你想通过fluwx在iOS端注册微信,请务必提供 `universalLink` ,否则无视这句话。乱填`universalLink`会导致iOS端微信SDK无法正常初始化!!!
![pub package](https://img.shields.io/pub/v/fluwx_no_pay.svg)
> NOTE: 别忘记替换 ^${latestVersion} !!!!
## 注册 WxAPI
> 注意:尽管可以通过Fluwx完成微信注册,但一些操作依然需要在对应平台进行设置,如配置iOS的*URLSchema,LSApplicationQueriesSchemes,universal link*等。
通过 `fluwx` 注册WxApi.
### 传送门
* [分享](./doc/SHARE_CN.md)
* [Auth](./doc/SEND_AUTH_CN.md)
* [支付](./doc/WXPay_CN.md)
* [打开小程序](./doc/LAUNCH_MINI_PROGRAM_CN.md)
* [一次性订阅消息](./doc/SUBSCRIBE_MESSAGE_CN.md)。。
* [二维码登录](./doc/AUTH_BY_QR_CODE_CN.md)
* [签约免密支付](./doc/AUTO_DEDUCT_CN.md)
* [接收微信响应](./doc/RESPONSE_CN.md)
```dart
registerWxApi(appId: "wxd930ea5d5a228f5f",universalLink: "https://your.univerallink.com/link/");
```
### Q&A
请先看文档,再看Q&A,再查看issue,自我排查错误,方便你我他。依然无法解决的问题可以加群提问。
* [常见问题Q&A](./doc/QUESTIONS_CN.md)
参数 `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`.
### 更多功能敬请请期待
## 能力文档
### 捐助
请作者喝杯咖啡。
- [基础知识](./docs/BASIC_KNOWLEDGE_CN.md)
- [分享](./docs/SHARE_CN.md)
- [支付](./dosc/PAYMENT_CN.md)
- [登录](./docs/AUTH_CN.md)
<img src="./arts/wx.jpeg" height="300"> <img src="./arts/ali.jpeg" height="300">
对于更多功能,可以查看源码。
### 欢迎关注公众号
![subscribe](./arts/wx_subscription.png)
### 捐助
开源不易,请作者喝杯咖啡。
<img src="https://github.com/JarvanMo/ImagesStore/blob/master/common/wx.jpeg" height="300"> <img src="https://github.com/JarvanMo/ImagesStore/blob/master/common/ali.jpeg" height="300">
## LICENSE
### 关注公众号
![subscribe](https://github.com/JarvanMo/ImagesStore/blob/master/fluwx/wx_subscription.png)
## LICENSE
Copyright 2018 OpenFlutter Project
......@@ -116,3 +99,8 @@ dependencies:
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
......@@ -2,14 +2,14 @@ group 'com.jarvan.fluwx'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.3.61'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.android.tools.build:gradle:3.6.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
......@@ -25,14 +25,14 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 29
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 16
consumerProguardFiles 'consumer-proguard-rules.txt'
consumerProguardFiles 'consumer-proguard-rules.txt'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
......@@ -42,9 +42,11 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.4.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0-M2'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2'
api 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:5.5.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'top.zibin:Luban:1.1.8'
implementation 'com.squareup.okhttp3:okhttp:4.0.0'
testImplementation 'junit:junit:4.12'
}
# 微信
-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
#Tue Aug 13 10:22:39 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jarvan.fluwx">
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"/>
<application>
<activity
android:name=".wxapi.WXEntryActivity"
android:launchMode="singleTask"
android:theme="@style/DisablePreviewTheme" />
<activity
android:name=".wxapi.WXPayEntryActivity"
android:name=".wxapi.FluwxWXEntryActivity"
android:launchMode="singleTask"
android:theme="@style/DisablePreviewTheme" />
......@@ -19,10 +16,9 @@
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
android:launchMode="singleTop"
android:targetActivity="com.jarvan.fluwx.wxapi.WXEntryActivity"
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" />
......@@ -33,7 +29,7 @@
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:launchMode="singleInstance"
android:targetActivity="com.jarvan.fluwx.wxapi.WXPayEntryActivity"
android:targetActivity="com.jarvan.fluwx.wxapi.FluwxWXEntryActivity"
android:theme="@style/DisablePreviewTheme">
......
/*___Generated_by_IDEA___*/
package com.jarvan.fluwx;
/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */
public final class BuildConfig {
public final static boolean DEBUG = Boolean.parseBoolean(null);
}
\ No newline at end of file
/*___Generated_by_IDEA___*/
package com.jarvan.fluwx;
/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */
public final class Manifest {
}
\ No newline at end of file
/*___Generated_by_IDEA___*/
package com.jarvan.fluwx;
/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */
public final class R {
}
\ No newline at end of file
/*
* Copyright (C) 2018 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;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.tencent.mm.opensdk.openapi.IWXAPI;
import com.tencent.mm.opensdk.openapi.WXAPIFactory;
public class AppRegister extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final IWXAPI api = WXAPIFactory.createWXAPI(context, null);
// 将该app注册到微信
}
}
package com.jarvan.fluwx.constant;
public class CallResult {
public static final String RESULT_DONE = "done";
public static final String RESULT_ERROR = "error";
public static final String RESULT_API_NULL = "WxApi Not Registered";
public static final String RESULT_WE_CHAT_NOT_INSTALLED = "wechat not installed";
public static final String RESULT_FILE_NOT_EXIST = "file not exists";
}
package com.jarvan.fluwx.constant;
public class WeChatPluginImageSchema {
public static final String SCHEMA_ASSETS = "assets://";
public static final String SCHMEA_HTTP = "http://";
public static final String SCHMEA_HTTPS = "https://";
public static final String SCHEMA_FILE = "file://";
public static final String SCHEMA_CONTENT = "content://";
}
package com.jarvan.fluwx.constant;
/***
* Created by mo on 2018/8/8
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
public class WeChatPluginMethods {
public static final String REGISTER_APP = "registerApp";
public static final String UNREGISTER_APP = "unregisterApp";
public static final String WE_CHAT_SHARE_RESPONSE = "onShareResponse";
public static final String WE_CHAT_LAUNCHMINIPROGRAM_RESPONSE = "onLaunchMiniProgramResponse";
public static final String ON_SUBSCRIBE_MSG_RESP = "onSubscribeMsgResp";
public static final String IS_WE_CHAT_INSTALLED = "isWeChatInstalled";
public static final String SHARE_TEXT = "shareText";
public static final String SHARE_IMAGE = "shareImage";
public static final String SHARE_MUSIC = "shareMusic";
public static final String SHARE_VIDEO = "shareVideo";
public static final String SHARE_WEB_PAGE = "shareWebPage";
public static final String SHARE_MINI_PROGRAM = "shareMiniProgram";
public static final String SHARE_FILE = "shareFile";
public static final String LAUNCH_MINI_PROGRAM = "launchMiniProgram";
public static final String PAY = "payWithFluwx";
public static final String WE_CHAT_PAY_RESPONSE = "onPayResponse";
public static final String SUBSCRIBE_MSG = "subscribeMsg";
public static final String AUTO_DEDUCT = "autoDeduct";
}
package com.jarvan.fluwx.constant;
/***
* Created by mo on 2018/8/8
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
public class WechatPluginKeys {
public static final String ANDROID = "android";
public static final String APP_ID = "appId";
public static final String PLATFORM = "platform";
public static final String RESULT = "result";
public static final String SCENE = "scene";
public static final String SCENE_TIMELINE = "WeChatScene.TIMELINE";
public static final String SCENE_SESSION = "WeChatScene.SESSION";
public static final String SCENE_FAVORITE = "WeChatScene.FAVORITE";
public static final String TRANSACTION = "transaction";
public static final String TEXT = "text";
public static final String TITLE = "title";
public static final String IMAGE = "image";
public static final String IMAGE_DATA = "imageData";
public static final String THUMBNAIL = "thumbnail";
public static final String DESCRIPTION = "description";
public static final String PACKAGE = "?package=";
public static final String MESSAGE_EXT = "messageExt";
public static final String MEDIA_TAG_NAME = "mediaTagName ";
public static final String MESSAGE_ACTION = "messageAction";
}
package com.jarvan.fluwx.handler
import com.tencent.mm.opensdk.modelbiz.WXOpenBusinessWebview
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.util.*
class FluwxAutoDeductHandler {
fun signAutoDeduct(call: MethodCall, result: MethodChannel.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 map = HashMap<String, String>()
map["appid"] = appId
map["mch_id"] = mchId
map["plan_id"] = planId
map["contract_code"] = contractCode
map["request_serial"] = requestSerial
map["contract_display_account"] = contractDisplayAccount
map["notify_url"] = notifyUrl
map["version"] = version
map["sign"] = sign
map["timestamp"] = timestamp
map["return_app"] = returnApp
val req = WXOpenBusinessWebview.Req()
req.businessType = businessType
req.queryInfo = map
val b = WXAPiHandler.wxApi?.sendReq(req)
result.success(b)
}
}
\ No newline at end of file
package com.jarvan.fluwx.handler
import com.jarvan.fluwx.constant.WechatPluginKeys
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
internal class FluwxLaunchMiniProgramHandler {
fun launchMiniProgram(call: MethodCall, result: MethodChannel.Result) {
val req = WXLaunchMiniProgram.Req()
req.userName = call.argument<String?>("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(mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
WechatPluginKeys.RESULT to done
))
}
}
\ No newline at end of file
/*
* Copyright (C) 2018 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.handler
import com.jarvan.fluwx.constant.CallResult
import com.jarvan.fluwx.constant.WechatPluginKeys
import com.tencent.mm.opensdk.modelpay.PayReq
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
class FluwxPayHandler {
fun pay(call: MethodCall, result: MethodChannel.Result) {
if (WXAPiHandler.wxApi == null) {
result.error(CallResult.RESULT_API_NULL, "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(
mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
WechatPluginKeys.RESULT to done
)
)
}
}
}
\ No newline at end of file
/*
* Copyright (C) 2018 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.handler
import io.flutter.plugin.common.PluginRegistry
object FluwxRequestHandler {
private var registrar: PluginRegistry.Registrar? = null
fun setRegistrar(reg: PluginRegistry.Registrar) {
registrar = reg
}
fun getRegistrar(): PluginRegistry.Registrar? {
return registrar;
}
}
\ No newline at end of file
package com.jarvan.fluwx.handler
import com.tencent.mm.opensdk.modelbiz.SubscribeMessage
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
/// create 2018/12/20 by cai
class FluwxSubscribeMsgHandler {
fun subScribeMsg(call: MethodCall, result: MethodChannel.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)
}
}
\ No newline at end of file
/*
* Copyright (C) 2018 The OpenFlutter Organization
* 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.
......@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.handler
package com.jarvan.fluwx.handlers
import com.tencent.mm.opensdk.diffdev.DiffDevOAuthFactory
......@@ -73,7 +73,6 @@ internal class FluwxAuthHandler(private val methodChannel: MethodChannel) {
// val schemeData = call.argument("schemeData")?:""
result.success(qrCodeAuth.auth(appId, scope, nonceStr, timeStamp, signature, qrCodeAuthListener))
}
fun stopAuthByQRCode(result: MethodChannel.Result) {
......
/*
* Copyright (C) 2018 The OpenFlutter Organization
* 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.
......@@ -13,10 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jarvan.fluwx.handler
package com.jarvan.fluwx.handlers
import com.jarvan.fluwx.constant.WeChatPluginMethods
import com.jarvan.fluwx.constant.WechatPluginKeys
import com.tencent.mm.opensdk.modelbase.BaseResp
import com.tencent.mm.opensdk.modelbiz.SubscribeMessage
import com.tencent.mm.opensdk.modelbiz.WXLaunchMiniProgram
......@@ -27,7 +25,6 @@ import com.tencent.mm.opensdk.modelpay.PayResp
import io.flutter.plugin.common.MethodChannel
object FluwxResponseHandler {
private var channel: MethodChannel? = null
private const val errStr = "errStr"
......@@ -39,7 +36,6 @@ object FluwxResponseHandler {
FluwxResponseHandler.channel = channel
}
fun handleResponse(response: BaseResp) {
when (response) {
is SendAuth.Resp -> handleAuthResponse(response)
......@@ -57,66 +53,51 @@ object FluwxResponseHandler {
"templateId" to response.templateID,
"action" to response.action,
"reserved" to response.reserved,
"scene" to response.scene
)
"scene" to response.scene,
type to response.type)
channel?.invokeMethod(WeChatPluginMethods.ON_SUBSCRIBE_MSG_RESP, result)
channel?.invokeMethod("onSubscribeMsgResp", result)
}
private fun handleLaunchMiniProgramResponse(response: WXLaunchMiniProgram.Resp) {
val result = mutableMapOf(
errStr to response.errStr,
WechatPluginKeys.TRANSACTION to response.transaction,
type to response.type,
errCode to response.errCode,
openId to response.openId,
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID
openId to response.openId
)
response.extMsg?.let {
// "extMsg" to response.extMsg,
result["extMsg"] = response.extMsg
}
channel?.invokeMethod(WeChatPluginMethods.WE_CHAT_LAUNCHMINIPROGRAM_RESPONSE, result)
channel?.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,
WechatPluginKeys.TRANSACTION to response.transaction,
type to response.type,
errCode to response.errCode,
openId to response.openId,
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID
errCode to response.errCode
)
channel?.invokeMethod(WeChatPluginMethods.WE_CHAT_PAY_RESPONSE, result)
channel?.invokeMethod("onPayResponse", result)
}
private fun handleSendMessageResp(response: SendMessageToWX.Resp) {
val result = mapOf(
errStr to response.errStr,
WechatPluginKeys.TRANSACTION to response.transaction,
type to response.type,
errCode to response.errCode,
openId to response.openId,
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID
)
channel?.invokeMethod(WeChatPluginMethods.WE_CHAT_SHARE_RESPONSE, result)
openId to response.openId)
channel?.invokeMethod("onShareResponse", result)
}
private fun handleAuthResponse(response: SendAuth.Resp) {
val result = mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
errCode to response.errCode,
"code" to response.code,
"state" to response.state,
......@@ -125,9 +106,7 @@ object FluwxResponseHandler {
errStr to response.errStr,
openId to response.openId,
"url" to response.url,
type to response.type,
WechatPluginKeys.TRANSACTION to response.transaction
)
type to response.type)
channel?.invokeMethod("onAuthResponse", result)
}
......@@ -135,18 +114,13 @@ object FluwxResponseHandler {
private fun handlerWXOpenBusinessWebviewResponse(response: WXOpenBusinessWebview.Resp) {
val result = mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
errCode to response.errCode,
"businessType" to response.businessType,
"resultInfo" to response.resultInfo,
errStr to response.errStr,
openId to response.openId,
type to response.type,
WechatPluginKeys.TRANSACTION to response.transaction
)
type to response.type)
channel?.invokeMethod("onAutoDeductResponse", result)
}
}
\ No newline at end of file
/*
* Copyright (C) 2018 The OpenFlutter Organization
* Copyright (c) 2020. OpenFlutter Project
*
* 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
* 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
* 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.
* 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.handler
package com.jarvan.fluwx.handlers
import com.jarvan.fluwx.constant.CallResult
import com.jarvan.fluwx.constant.WechatPluginKeys
import android.content.Context
import com.tencent.mm.opensdk.openapi.IWXAPI
import com.tencent.mm.opensdk.openapi.WXAPIFactory
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
object WXAPiHandler {
private var registrar: PluginRegistry.Registrar? = null
var wxApi: IWXAPI? = null
private var context: Context? = null
fun setRegistrar(registrar: PluginRegistry.Registrar) {
WXAPiHandler.registrar = registrar
fun setContext(context: Context?) {
WXAPiHandler.context = context
}
fun registerApp(call: MethodCall, result: MethodChannel.Result) {
if (call.argument<Boolean>(WechatPluginKeys.ANDROID) == false) {
if (call.argument<Boolean?>("android") == false) {
return
}
if (wxApi != null) {
result.success(mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
WechatPluginKeys.RESULT to true
))
result.success(true)
return
}
val appId: String? = call.argument(WechatPluginKeys.APP_ID)
val appId: String? = call.argument("appId")
if (appId.isNullOrBlank()) {
result.error("invalid app id", "are you sure your app id is correct ?", appId)
return
}
val api = WXAPIFactory.createWXAPI(registrar!!.context().applicationContext, appId)
val api = WXAPIFactory.createWXAPI(context?.applicationContext, appId)
val registered = api.registerApp(appId)
wxApi = api
result.success(mapOf(
WechatPluginKeys.PLATFORM to WechatPluginKeys.ANDROID,
WechatPluginKeys.RESULT to registered
))
result.success(registered)
}
fun checkWeChatInstallation(result: MethodChannel.Result) {
if (wxApi == null) {
result.error(CallResult.RESULT_API_NULL, "please config wxapi first", null)
result.error("Unassigned WxApi", "please config wxapi first", null)
return
} else {
result.success(wxApi!!.isWXAppInstalled)
result.success(wxApi?.isWXAppInstalled)
}
}
......
package com.jarvan.fluwx.io
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okio.*
import top.zibin.luban.Luban
import java.io.*
import java.util.*
import kotlin.math.sqrt
/***
* Created by mo on 2020/3/7
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class ImagesIOIml(override val image: WeChatImage) : 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))
val compressedFile = Luban
.with(context)
.ignoreBy(maxSize)
.setTargetDir(context.cacheDir.absolutePath)
.get(originFile.absolutePath)
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: WeChatImage
suspend fun readByteArray(): ByteArray
suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray
}
internal suspend fun ByteArray.toExternalCacheFile(context: Context, suffix: String): File? {
val byteArray = this
return withContext(Dispatchers.IO) {
var file: File? = null
var sink: BufferedSink? = null
var source: Source? = null
var outputStream: OutputStream? = null
try {
val externalFile = context.externalCacheDir ?: return@withContext file
file = File(externalFile.absolutePath + File.separator + UUID.randomUUID().toString() + suffix)
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 external files")
} finally {
sink?.close()
source?.close()
outputStream?.close()
}
file
}
}
\ No newline at end of file
package com.jarvan.fluwx.io
import android.content.Context
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/3/7
* 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/
class WeChatFileImage(override val source: Any, override val suffix: String) : WeChatImage {
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 WeChatAssetImage(override val source: Any, override val suffix: String) : WeChatImage {
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 WeChatNetworkImage(override val source: Any, override val suffix: String) : WeChatImage {
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 WeChatMemoryImage(override val source: Any, override val suffix: String) : WeChatImage {
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 WeChatImage {
val source: Any
val suffix: String
suspend fun readByteArray(): ByteArray
companion object {
// NETWORK,
// ASSET,
// FILE,
// BINARY,
fun createWeChatImage(params: Map<String, Any>, assetFileDescriptor: AssetFileDescriptor, context: Context): WeChatImage {
// Map toMap() => {"source": source, "schema": schema.index, "suffix": suffix};
val suffix = (params["suffix"] as String?) ?: ".jpeg"
return when ((params["schema"] as? Int) ?: 0) {
0 -> WeChatNetworkImage(source = (params["source"] as? String).orEmpty(), suffix = suffix)
1 -> {
// val source = (params["source"] as? String).orEmpty()
// val uri = Uri.parse(source)
// val packageName = uri.getQueryParameter("package")
// val subPath = if (packageName.isNullOrBlank()) {
// flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty())
// } else {
// flutterAssets.getAssetFilePathBySubpath(uri.path.orEmpty(), packageName)
// }
WeChatAssetImage(source = assetFileDescriptor, suffix = suffix)
}
2 -> WeChatFileImage(source = (params["source"] as? String).orEmpty(), suffix = suffix)
3 -> WeChatMemoryImage(source = (params["source"] as? ByteArray)
?: byteArrayOf(), suffix = suffix)
else -> WeChatNetworkImage(source = (params["source"] as? String).orEmpty(), suffix = suffix)
}
}
}
}
/*
* Copyright (C) 2018 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.utils;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.text.TextUtils;
import java.io.IOException;
import io.flutter.plugin.common.PluginRegistry;
public final class AssetManagerUtil {
private AssetManagerUtil() {
throw new RuntimeException("can't do this");
}
public static AssetFileDescriptor openAsset(PluginRegistry.Registrar registrar, String assetKey, String assetPackage) {
AssetFileDescriptor fd = null;
AssetManager assetManager = registrar.context().getAssets();
String key;
if (TextUtils.isEmpty(assetPackage)) {
key = registrar.lookupKeyForAsset(assetKey);
} else {
key = registrar.lookupKeyForAsset(assetKey, assetPackage);
}
try {
fd = assetManager.openFd(key);
} catch (IOException e) {
e.printStackTrace();
}
return fd;
}
}
/*
* Copyright (C) 2018 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.utils;
import android.content.res.AssetFileDescriptor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
public class FileUtil {
public static File createTmpFile(AssetFileDescriptor fileDescriptor) {
if (fileDescriptor == null) {
return null;
}
File file = null;
BufferedSink sink = null;
Source source = null;
OutputStream outputStream = null;
try {
file = File.createTempFile(UUID.randomUUID().toString(), ".png");
outputStream = new FileOutputStream(file);
sink = Okio.buffer(Okio.sink(outputStream));
source = Okio.source(fileDescriptor.createInputStream());
sink.writeAll(source);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (sink != null) {
try {
sink.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (source != null) {
try {
source.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
}
/*
* Copyright (C) 2018 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.utils;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import com.jarvan.fluwx.constant.WeChatPluginImageSchema;
import com.jarvan.fluwx.constant.WechatPluginKeys;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import io.flutter.plugin.common.PluginRegistry;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
public class ShareImageUtil {
final static int WX_MAX_IMAGE_BYTE_SIZE = 10485760;
public static byte[] getImageData(PluginRegistry.Registrar registrar, String path) {
byte[] result = null;
if (path.startsWith(WeChatPluginImageSchema.SCHEMA_ASSETS)) {
String key = path.substring(WeChatPluginImageSchema.SCHEMA_ASSETS.length());
AssetFileDescriptor fileDescriptor = AssetManagerUtil.openAsset(registrar, key, getPackage(key));
try {
InputStream inputStream = fileDescriptor.createInputStream();
result = streamToByteArray(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
} else if (path.startsWith(WeChatPluginImageSchema.SCHEMA_FILE)) {
String pathWithoutUri = path.substring("file://".length());
result = fileToByteArray(registrar, pathWithoutUri);
} else if (path.startsWith(WeChatPluginImageSchema.SCHEMA_CONTENT)) {
File file = getFileFromContentProvider(registrar, path);
if (file != null) {
result = fileToByteArray(registrar, file.getAbsolutePath());
}
} else {
// result = handleNetworkImage(registrar, path);
result = Util.inputStreamToByte(openStream(path));
}
return result;
}
private static byte[] streamToByteArray(InputStream inputStream) {
Bitmap bmp = null;
bmp = BitmapFactory.decodeStream(inputStream);
return Util.bmpToByteArray(bmp, true);
}
private static byte[] fileToByteArray(File file) {
Bitmap bmp = null;
bmp = BitmapFactory.decodeFile(file.getAbsolutePath());
return Util.bmpToByteArray(bmp, true);
}
private static byte[] fileToByteArray(PluginRegistry.Registrar registrar, String pathWithoutUri) {
byte[] result = null;
Bitmap bmp = null;
bmp = BitmapFactory.decodeFile(pathWithoutUri);
int byteCount;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
byteCount = bmp.getAllocationByteCount();
} else {
byteCount = bmp.getByteCount();
}
if (byteCount >= WX_MAX_IMAGE_BYTE_SIZE) {
result = Util.bmpToCompressedByteArray(bmp, Bitmap.CompressFormat.JPEG, true);
} else {
result = Util.bmpToByteArray(bmp, true);
}
return result;
}
private static String getPackage(String assetsName) {
String packageStr = null;
if (assetsName.contains(WechatPluginKeys.PACKAGE)) {
int index = assetsName.indexOf(WechatPluginKeys.PACKAGE);
packageStr = assetsName.substring(index + WechatPluginKeys.PACKAGE.length(), assetsName.length());
}
return packageStr;
}
public static File inputStreamToFile(InputStream inputStream, String suffix, Context context) {
File file = null;
BufferedSink sink = null;
Source source = null;
OutputStream outputStream = null;
try {
File externalFile = context.getExternalCacheDir();
if (externalFile == null) {
return null;
}
file = new File(externalFile.getAbsolutePath() + File.separator + UUID.randomUUID().toString() + suffix);
// file = File.createTempFile(UUID.randomUUID().toString(), suffix);
outputStream = new FileOutputStream(file);
sink = Okio.buffer(Okio.sink(outputStream));
source = Okio.source(inputStream);
sink.writeAll(source);
sink.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (sink != null) {
try {
sink.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (source != null) {
try {
source.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
private static InputStream openStream(String url) {
if (!url.startsWith("https") && !url.startsWith("http")) {
url = "http://" + url;
}
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url(url).get().build();
try {
Response response = okHttpClient.newCall(request).execute();
ResponseBody responseBody = response.body();
if (response.isSuccessful() && responseBody != null) {
return responseBody.byteStream();
} else {
return null;
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static File getFileFromContentProvider(PluginRegistry.Registrar registrar, String path) {
Source source = null;
BufferedSink sink = null;
File file = null;
try {
Context context = registrar.context().getApplicationContext();
Uri uri = Uri.parse(path);
String suffix = null;
String mimeType = context.getContentResolver().getType(uri);
if (TextUtils.equals(mimeType, "image/jpeg") || TextUtils.equals(mimeType, "image/jpg")) {
suffix = ".jpg";
} else if (TextUtils.equals(mimeType, "image/png")) {
suffix = ".png";
}
file = File.createTempFile(UUID.randomUUID().toString(), suffix);
InputStream inputStream = context.getContentResolver().openInputStream(uri);
if (inputStream == null) {
return null;
}
OutputStream outputStream = new FileOutputStream(file);
sink = Okio.buffer(Okio.sink(outputStream));
source = Okio.source(inputStream);
sink.writeAll(source);
source.close();
sink.close();
} catch (IOException e) {
Log.i("fluwx", "reading image failed:\n" + e.getMessage());
}
return file;
}
}
/*
* Copyright (C) 2018 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.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ThumbnailCompressUtil {
/*** 图片压缩比例计算**
* @param options BitmapFactory.Options* @param minSideLength 小边长,单位为像素,如果为-1,则不按照边来压缩图片*
* @param maxNumOfPixels 这张片图片最大像素值,单位为byte,如100*1024* @return 压缩比例,必须为2的次幂*/
public static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
/*** 计算图片的压缩比例,用于图片压缩
* * @param options BitmapFactory.Options* @param minSideLength 小边长,单位为像素,如果为-1,则不按照边来压缩图片
* * @param maxNumOfPixels 这张片图片最大像素值,单位为byte,如100*1024*
* @return 压缩比例*/
private static int computeInitialSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math.floor(w / minSideLength), Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
public static Bitmap makeNormalBitmap(String nativeImagePath, int minSideLength, int maxNumOfPixels) {
return makeNormalBitmap(nativeImagePath, minSideLength, maxNumOfPixels, Bitmap.Config.ARGB_4444);
}
public static Bitmap makeNormalBitmap(String nativeImagePath, int minSideLength, int maxNumOfPixels, Bitmap.Config config) {
Bitmap.CompressFormat format = Bitmap.CompressFormat.JPEG;
if (nativeImagePath.toLowerCase().endsWith(".png")) {
format = Bitmap.CompressFormat.PNG;
}
// ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Bitmap bitmap = BitmapFactory.decodeFile(nativeImagePath);
// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inPreferredConfig = config;
// options.outHeight = bitmap.getHeight();
// options.outWidth = bitmap.getWidth();
// int quality = computeSampleSize(options, minSideLength, maxNumOfPixels);
// bitmap.compress(format, quality, baos);
//
// byte[] bytes = baos.toByteArray();
// bitmap.recycle();
// Bitmap result = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
// try {
// baos.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
Bitmap bitmap = BitmapFactory.decodeFile(nativeImagePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100; //此处可尝试用90%开始压缩,跳过100%压缩
// 循环判断如果压缩后图片是否大于100kb,大于继续压缩
int length;
while ((length = baos.toByteArray().length) / 1024 > 32) {
// 每次都减少10
options -= 10;
// 重置baos即清空baos
baos.reset();
// 这里压缩options%,把压缩后的数据存放到baos中
if (options <= 0) {
options = 0;
}
bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
if (options == 0) {
break;
}
}
return bitmap;
}
public static Bitmap compress(String nativeImagePath) {
Bitmap.CompressFormat format = Bitmap.CompressFormat.JPEG;
if (nativeImagePath.toLowerCase().endsWith(".png")) {
format = Bitmap.CompressFormat.PNG;
}
Log.e("tag", nativeImagePath);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Bitmap bitmap = BitmapFactory.decodeFile(nativeImagePath);
bitmap.compress(format, 90, baos);
byte[] bytes = baos.toByteArray();
bitmap.recycle();
Bitmap result = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
public static Bitmap createScaledBitmapWithRatio(Bitmap bitmap, float thumbWidth, boolean recycle) {
Bitmap thumb;
int imagw = bitmap.getWidth();
int imagh = bitmap.getHeight();
if (imagh > imagw) {
int height = (int) (imagh * thumbWidth / imagw);
thumb = Bitmap.createScaledBitmap(bitmap, (int) thumbWidth, height, true);
} else {
int width = (int) (imagw * thumbWidth / imagh);
thumb = Bitmap.createScaledBitmap(bitmap, width, (int) thumbWidth, true);
}
if (recycle) {
bitmap.recycle();
}
return thumb;
}
public static Bitmap createScaledBitmap(Bitmap bitmap, int size, boolean recycle) {
Bitmap thumb;
thumb = Bitmap.createScaledBitmap(bitmap, size, size, true);
if (recycle) {
bitmap.recycle();
}
return thumb;
}
public static Bitmap createScaledBitmapWithRatio(Bitmap bitmap, int maxLength, boolean recycle) {
Bitmap result = bitmap;
while (true) {
double ratio = ((double) maxLength) / result.getByteCount();
double width = result.getWidth() * Math.sqrt(ratio);
double height = result.getHeight() * Math.sqrt(ratio);
Bitmap tmp = Bitmap.createScaledBitmap(result, (int) width, (int) height, true);
if (result != bitmap) {
result.recycle();
}
result = tmp;
if (result.getByteCount() < maxLength) {
break;
}
}
if (recycle) {
bitmap.recycle();
}
return result;
}
public static byte[] bmpToByteArray(final Bitmap bmp, Bitmap.CompressFormat format, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(format, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
/*
* Copyright (C) 2018 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.utils;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
class Util {
private static final String TAG = "SDK_Sample.Util";
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
return bmpToByteArray(bmp, CompressFormat.PNG, needRecycle);
}
public static byte[] bmpToCompressedByteArray(final Bitmap bmp, CompressFormat format, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(format, 25, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static byte[] bmpToByteArray(final Bitmap bmp, CompressFormat format, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(format, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static byte[] bmpToByteArray2(final Bitmap bmp, final boolean needRecycle) {
int i;
int j;
if (bmp.getHeight() > bmp.getWidth()) {
i = bmp.getWidth();
j = bmp.getWidth();
} else {
i = bmp.getHeight();
j = bmp.getHeight();
}
Bitmap localBitmap = Bitmap.createBitmap(i, j, Bitmap.Config.ARGB_4444);
Canvas localCanvas = new Canvas(localBitmap);
while (true) {
localCanvas.drawBitmap(bmp, new Rect(0, 0, i, j), new Rect(0, 0, i, j), null);
if (needRecycle)
bmp.recycle();
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
localBitmap.compress(Bitmap.CompressFormat.JPEG, 100,
localByteArrayOutputStream);
localBitmap.recycle();
byte[] arrayOfByte = localByteArrayOutputStream.toByteArray();
try {
localByteArrayOutputStream.close();
return arrayOfByte;
} catch (Exception e) {
// F.out(e);
}
i = bmp.getHeight();
j = bmp.getHeight();
}
}
public static byte[] getHtmlByteArray(final String url) {
URL htmlUrl = null;
InputStream inStream = null;
try {
htmlUrl = new URL(url);
URLConnection connection = htmlUrl.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
inStream = httpConnection.getInputStream();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
byte[] data = inputStreamToByte(inStream);
return data;
}
public static byte[] inputStreamToByte(InputStream is) {
try {
ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
int ch;
while ((ch = is.read()) != -1) {
bytestream.write(ch);
}
byte imgdata[] = bytestream.toByteArray();
bytestream.close();
return imgdata;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] readFromFile(String fileName, int offset, int len) {
if (fileName == null) {
return null;
}
File file = new File(fileName);
if (!file.exists()) {
Log.i(TAG, "readFromFile: file not found");
return null;
}
if (len == -1) {
len = (int) file.length();
}
Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len));
if (offset < 0) {
Log.e(TAG, "readFromFile invalid offset:" + offset);
return null;
}
if (len <= 0) {
Log.e(TAG, "readFromFile invalid len:" + len);
return null;
}
if (offset + len > (int) file.length()) {
Log.e(TAG, "readFromFile invalid file len:" + file.length());
return null;
}
byte[] b = null;
try {
RandomAccessFile in = new RandomAccessFile(fileName, "r");
b = new byte[len]; // ���������ļ���С������
in.seek(offset);
in.readFully(b);
in.close();
} catch (Exception e) {
Log.e(TAG, "readFromFile : errMsg = " + e.getMessage());
e.printStackTrace();
}
return b;
}
private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440;
public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) {
// Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0);
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inJustDecodeBounds = true;
Bitmap tmp = BitmapFactory.decodeFile(path, options);
if (tmp != null) {
tmp.recycle();
tmp = null;
}
Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop);
final double beY = options.outHeight * 1.0 / height;
final double beX = options.outWidth * 1.0 / width;
Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY);
options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));
if (options.inSampleSize <= 1) {
options.inSampleSize = 1;
}
// NOTE: out of memory error
while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {
options.inSampleSize++;
}
int newHeight = height;
int newWidth = width;
if (crop) {
if (beY > beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
} else {
if (beY < beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
}
options.inJustDecodeBounds = false;
Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize);
Bitmap bm = BitmapFactory.decodeFile(path, options);
if (bm == null) {
Log.e(TAG, "bitmap decode failed");
return null;
}
Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight());
final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
if (scale != null) {
bm.recycle();
bm = scale;
}
if (crop) {
final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);
if (cropped == null) {
return bm;
}
bm.recycle();
bm = cropped;
Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight());
}
return bm;
} catch (final OutOfMemoryError e) {
Log.e(TAG, "decode bitmap failed: " + e.getMessage());
options = null;
}
return null;
}
}
/*
* Copyright (C) 2018 The OpenFlutter Organization
* 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.
......@@ -18,9 +18,8 @@ package com.jarvan.fluwx.wxapi
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import com.jarvan.fluwx.handler.FluwxRequestHandler
import com.jarvan.fluwx.handler.FluwxResponseHandler
import com.jarvan.fluwx.handler.WXAPiHandler
import com.jarvan.fluwx.handlers.FluwxResponseHandler
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
......@@ -28,20 +27,18 @@ import com.tencent.mm.opensdk.openapi.IWXAPIEventHandler
open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
// IWXAPI 是第三方app和微信通信的openapi接口
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
try {
WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) {
e.printStackTrace()
startSpecifiedActivity()
finish()
}
}
override fun onNewIntent(intent: Intent) {
......@@ -53,6 +50,7 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
WXAPiHandler.wxApi?.handleIntent(intent, this)
} catch (e: Exception) {
e.printStackTrace()
startSpecifiedActivity()
finish()
}
}
......@@ -61,11 +59,9 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
override fun onReq(baseReq: BaseReq) {
// FIXME: 可能是官方的Bug,从微信拉起APP的Intent类型不对,无法跳转回Flutter Activity
// 稳定复现场景:微信版本为7.0.5,小程序SDK为2.7.7
val activity = FluwxRequestHandler.getRegistrar()?.activity()
if (baseReq.type == 4 && activity is Activity) {
if (baseReq.type == 4) {
// com.tencent.mm.opensdk.constants.ConstantsAPI.COMMAND_SHOWMESSAGE_FROM_WX = 4
startActivity(Intent(this, activity::class.java))
finish()
startSpecifiedActivity()
}
}
......@@ -75,5 +71,10 @@ open class FluwxWXEntryActivity : Activity(), IWXAPIEventHandler {
finish()
}
private fun startSpecifiedActivity() {
Intent("$packageName.FlutterActivity").run {
startActivity(this)
}
finish()
}
}
\ No newline at end of file
/*
* Copyright (C) 2018 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
open class WXEntryActivity : FluwxWXEntryActivity()
\ No newline at end of file
/*
* Copyright (C) 2018 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
open class WXPayEntryActivity : FluwxWXEntryActivity()
\ No newline at end of file
package com.jarvan.fluwx
class FluwxTest {
fun test(){}
}
\ No newline at end of file
## AUTH BY QR CODE
When WeChat not installed on devices, user can login with WeChat-QRCode.
### Flutter
Request QRCode by the following codes:
```dart
fluwx.authByQRCode(
appId: "wxd930ea5d5a258f4f",
scope: "noncestr",
nonceStr: "nonceStr",
timeStamp: "1417508194",
signature: "429eaaa13fd71efbc3fd344d0a9a9126835e7303");
}
```
[What do the params mean?](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=215238808828h4XN&token=&lang=zh_CN)
You can receive the data from WeChat through these ways:
```dart
//listening your auth status
fluwx.onAuthByQRCodeFinished.listen((data){
setState(() {
_status =
"errorCode=>${data.errorCode}\nauthCode=>${data.authCode}";
});
});
//show your qrcode after this
fluwx.onAuthGotQRCode.listen((image) {
setState(() {
_image = image;
});
});
//qrcode was scanned
fluwx.onQRCodeScanned.listen((scanned) {
setState(() {
_status = "scanned";
});
});
```
### Android
WeChatSDK will crash due to `HttpClient` when running on Android P,see this [solution](https://cloud.tencent.com/developer/ask/146536) for help .
## 二维码登录
如果用户没有安装微信,我们可以通过扫描二维码登录.
### Flutter
请求一个二维码:
```dart
fluwx.authByQRCode(
appId: "wxd930ea5d5a258f4f",
scope: "noncestr",
nonceStr: "nonceStr",
timeStamp: "1417508194",
signature: "429eaaa13fd71efbc3fd344d0a9a9126835e7303");
}
```
[这些参数都是什么意思?](https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=215238808828h4XN&token=&lang=zh_CN)
通过以下方式监听扫描过程:
```dart
//当扫码完成
fluwx.onAuthByQRCodeFinished.listen((data){
setState(() {
_status =
"errorCode=>${data.errorCode}\nauthCode=>${data.authCode}";
});
});
//这个时候可以显示你的二维码了
fluwx.onAuthGotQRCode.listen((image) {
setState(() {
_image = image;
});
});
//二维码被扫描了
fluwx.onQRCodeScanned.listen((scanned) {
setState(() {
_status = "scanned";
});
});
```
### Android
在Android P上,微信SDK会闪退, 查看[该文章](https://cloud.tencent.com/developer/ask/146536)以寻求帮助.
## SIGN AUTO-DEDUCT
see [details](https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_5&index=2).
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.autoDeDuct(
appId: "",
mchId: "",
planId: "",
contractCode: "",
requestSerial: "",
contractDisplayAccount: "",
notifyUrl: "",
version: "",
sign: "",
timestamp: "",
returnApp: '3');
```
\ No newline at end of file
## 签约微信免密支付
查看 [详情](https://pay.weixin.qq.com/wiki/doc/api/pap.php?chapter=18_5&index=2).
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.autoDeDuct(
appId: "",
mchId: "",
planId: "",
contractCode: "",
requestSerial: "",
contractDisplayAccount: "",
notifyUrl: "",
version: "",
sign: "",
timestamp: "",
returnApp: '3');
```
\ No newline at end of file
## LAUNCH MINI-PROGRAM
`Fluwx` can launch mini-program now.
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.launchMiniProgram(
username: "gh_d43f693ca31f"
);
```
\ No newline at end of file
## LAUNCH MINI-PROGRAM
`Fluwx` 现在可以拉起小程序了.
```dart
import 'package:fluwx/fluwx.dart' as fluwx;
fluwx.launchMiniProgram(
username: "gh_d43f693ca31f"
);
```
\ No newline at end of file
## WeChat Not Installed on iOS?
if you have installed WeChat on your iPhone but you still catch an exception called "wechat not installed",just add the following
code to your *info.plist*:
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
```
## Can't Launch WeChat on Android?
Check your signature please.
## Failed to notify project evalution listener
[Failed to notify project evalution listener](https://www.jianshu.com/p/f74fed94be96)
## Can't receive response after upgrading to 1.0.0 on iOS
There's no need to override `AppDelegate` since `fluwx 1.0.0`. If you have did thad before, please remove
the following code in your `AppDelegate`:
```objective-c
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [WXApi handleOpenURL:url delegate:[FluwxResponseHandler defaultManager]];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
return [WXApi handleOpenURL:url delegate:[FluwxResponseHandler defaultManager]];
}
```
If you have to override these two functions,make sure you have called the `super`:
```objective-c
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [super application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
return [super application:application openURL:url options:options];
}
```
**!!!!请先看[文档](https://github.com/OpenFlutter/fluwx/blob/master/README_CN.md),再看常见Q&A,再查看issue,自我排查错误,方便你我他。依然无法解决的问题可以加群提问, QQ Group:892398530。!!!!**
## 常见Q&A
#### Fluwx调起失败?
请检查APPID、包名、以及App签名是否一致。debug 和release的签名默认不一样,请注意。
#### Android Flutter编译失败
1、检查Kotlin版本,打开```build.gradle```文件,查看以下配置
```
buildscript {
······
ext.kotlin_version = '1.3.11'
······
}
```
确保项目中使用的Kotlin版本符合要求;
2、检查Android目录下```build.gradle```文件中gradle插件版本:```classpath 'com.android.tools.build:gradle:3.2.1'``````gradle-wrapper.properties```文件中的gradle版本是否匹配:```distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip```,两者的匹配规则见Android官网:[Update Gradle](https://developer.android.com/studio/releases/gradle-plugin.html#updating-gradle)
#### WeChat Not Installed on iOS?
iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。
受此影响,当你的应用在iOS 9中需要使用微信SDK的相关能力(分享、收藏、支付、登录等)时,需要在“Info.plist”里增加如下代码:
```xml
<key>LSApplicationQueriesSchemes</key>
<array>
<string>weixin</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
```
#### 如果没有安装微信,微信登录不了,导致iOS审核失败
fluwx提供了检查用户是否安装微信的方法:```isWeChatInstalled()```,iOS使用微信相关功能前,务必先检查微信是否安装。
#### Failed to notify project evalution listener
[Failed to notify project evalution listener](https://www.jianshu.com/p/f74fed94be96)
#### 微信登录不能触发fluwx.responseFromAuth.listen监听回调
请先看文档:[微信调回](https://github.com/OpenFlutter/fluwx/blob/master/doc/RESPONSE_CN.md) 。Android端如果是混合开发,请注册```WXEntryActivity```and```WXPayEntryActivity```;从1.0.0以后iOS端不需要重写```AppDelegate```中的相关方法,如果需要请务必调用相应super方法。
#### isWeChatInstalled返回false
请查看该 [issue](https://github.com/OpenFlutter/fluwx/issues/34) ,检查```AppDelegate```中配置是否正确。
#### Kotlin报错:XXX is only available since Kotlin 1.3 and cannot be used in Kotlin 1.2
1、请检查IDE安装的Kotlin插件版本是否符合fluwx要求:AS打开设置-->Plugin-->Koltin查看插件版本;
2、请检查项目中使用的Kotlin版本:打开```build.gradle```文件,查看以下配置
```
buildscript {
······
ext.kotlin_version = '1.3.11'
······
}
```
#### listen监听多次调用
请查看该 [issue](https://github.com/OpenFlutter/fluwx/issues/36) 。这个问题是由于listen被多次注册导致的,使用者自己代码的问题,非fluwx导致的,请在合适的时机将listen cancel掉:
```
StreamSubscription<WeChatAuthResponse> _wxlogin;
_wxlogin = fluwx.responseFromAuth.listen((val) {})
@override
void dispose() {
_wxlogin.cancel();
}
```
#### 分享完成或者取消分享后App崩溃
如果你手动注册了```WXEntryActivity```and```WXPayEntryActivity```,请检查```Manifest```中包名是否写对了。
#### IOS编译错误:No such module 'fluwx'
如果项目本身是在Android环境配置的,移到iOS的环境的时候,会出现该问题,请按照正常步骤配置。
#### 支付成功后,按物理按键或手机自动返回商户APP,监听不到返回数据
有人反应会出现```fluwx.responseFromPayment.listen```监听无效,无法获取支付结果,建议可以直接向服务器查询是否成功。
#### iOS报错:Specs satisfying the `fluwx (from `.symlinks/plugins/fluwx/ios`)` dependency were found, but they required a higher minimum deployment target.
请在在pod file里将iOS项目deployment target改到9.0。
#### ResponseType与Dio插件中的命名冲突
使用as的方式导包即可:```import 'package:fluwx/fluwx.dart' as fluwx;```
差异被折叠。
### Response From WeChat
There's some work we have to do on the particular platform(if you don't need this,just ignore).
### Flutter
We can get the reponse from WeChat after sharing and etc:
```dart
fluwx.responseFromShare.listen((response){
//do something
});
fluwx.responseFromAuth.listen((response){
//do something
});
fluwx.responseFromPayment.listen((response){
//do something
});
```
> NOTE:If the field starts with "android" or "iOS", it means that only android or iOS has the field.
The type of return value is `WeChatResponse`,and `type` is an enum:
```dart
enum WeChatResponseType {
SHARE,
AUTH,
PAYMENT }
```
### Android
Fluwx will create `WXEntryActivity`or`WXPayEntryActivity` by itself since *0.4.0*. So the following
code isn't necessary.
~~For`Android`,create `WXEntryActivity`or`WXPayEntryActivity`,and override the following function:~~
```kotlin
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WXAPiHandler.wxApi?.handleIntent(intent, this)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
WXAPiHandler.wxApi?.handleIntent(intent, this)
}
override fun onResp(resp: BaseResp) {
FluwxResponseHandler.handleResponse(resp)
finish()
}
```
~~You can also directly inherit `FluwxWXEntryActivity`,and then you can do nothing.
For the rule of creating `WXEntryActivity` and `WXPayEntryActivity`,please read [example wxapi](https://github.com/OpenFlutter/fluwx/tree/master/example/android/app/src/main/kotlin/net/sourceforge/simcpux/wxapi )~~
~~,never forget to register your Activity in `AndroidManifest.mxl`:~~
```xml
<activity
android:name="your.package.name.registered.on.wechat.wxapi.WXEntryActivity"
android:theme="@style/DisablePreviewTheme"
android:exported="true"
android:launchMode="singleTop"/>
<activity
android:name="your.package.name.registered.on.wechat.wxapi.WXPayEntryActivity"
android:theme="@style/DisablePreviewTheme"
android:exported="true"
android:launchMode="singleTop"/>
```
#### However Customization Is Always Good
Well, sometimes you need to create `WXEntryActivity`and`WXPayEntryActivity` by yourself because your project isn't
a pure-flutter-project. The `WXEntryActivity`and`WXPayEntryActivity` must be under *packageName/wxapi/*,you
can inherit `FluwxWXEntryActivity` for convenience.Then register `WXEntryActivity`and`WXPayEntryActivity`in
`AndroidManifest.mxl`:
```
<activity android:name=".wxapi.WXEntryActivity"
android:theme="@style/DisablePreviewTheme"
/>
<activity android:name=".wxapi.WXPayEntryActivity"
android:theme="@style/DisablePreviewTheme"/>
<activity-alias
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
tools:replace="android:targetActivity"
android:targetActivity=".wxapi.WXEntryActivity"
android:launchMode="singleTop">
<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
tools:replace="android:targetActivity"
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:targetActivity=".wxapi.WXPayEntryActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
```
### iOS
don't override this since 1.0.0:
~~override the following function in`AppDelegate`:~~
```objective-c
- (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]];
}
```
If you have to override these two functions, please make sure you have called `super`:
```
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [super application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
return [super application:application openURL:url options:options];
}
```
> NOTE:Don't forget to add URL Schema in order to go back to your app.
### 微信调回
微信的回调也要根据平台的不同进行差异化处理(如果你不需要回调,请忽略)。
### Flutter
```dart
fluwx.responseFromShare.listen((response){
//do something
});
fluwx.responseFromAuth.listen((response){
//do something
});
fluwx.responseFromPayment.listen((response){
//do something
});
```
> 注意:如果一个字段以*android*或者*iOS*开头,那么意味这个字段只存在于*android*或者*iOS*。
### Android
*0.4.0*开始,开发者不必手动添加`WXEntryActivity``WXPayEntryActivity`了,所以下面的不是必需要的了:
~~由于机制问题,`Android`端需要在`WXEntryActivity``WXPayEntryActivity`中添加如下代码:~~
```kotlin
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WXAPiHandler.wxApi?.handleIntent(intent, this)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
WXAPiHandler.wxApi?.handleIntent(intent, this)
}
override fun onResp(resp: BaseResp) {
FluwxResponseHandler.handleResponse(resp)
finish()
}
```
~~你也可以直接继承`FluwxWXEntryActivity`。~~
~~`WXEntryActivity``WXPayEntryActivity`创建规则请参阅官方文档。具体可以参考[example wxapi](https://github.com/OpenFlutter/fluwx/tree/master/example/android/app/src/main/kotlin/net/sourceforge/simcpux/wxapi )~~
~~,也不要忘记在`AndroidManifest.mxl`中注册:~~
```xml
<activity
android:name="your.package.name.registered.on.wechat.wxapi.WXEntryActivity"
android:theme="@style/DisablePreviewTheme"
android:exported="true"
android:launchMode="singleTop"/>
<activity
android:name="your.package.name.registered.on.wechat.wxapi.WXPayEntryActivity"
android:theme="@style/DisablePreviewTheme"
android:exported="true"
android:launchMode="singleTop"/>
```
#### 但个性化总是好的
有的时候开者仍然需要手动创建`WXEntryActivity``WXPayEntryActivity`,比如这并不是一个纯净的Flutter的项目,仍有一部分需要
原生实现。`WXEntryActivity`and`WXPayEntryActivity` 必须在 *packageName/wxapi/*下面,方便起见,你可以直接继承 `FluwxWXEntryActivity`
然后在`AndroidManifest.mxl`中注册`WXEntryActivity`and`WXPayEntryActivity`:
```
<activity android:name=".wxapi.WXEntryActivity"
android:theme="@style/DisablePreviewTheme"
/>
<activity android:name=".wxapi.WXPayEntryActivity"
android:theme="@style/DisablePreviewTheme"/>
<activity-alias
android:name="${applicationId}.wxapi.WXEntryActivity"
android:exported="true"
tools:replace="android:targetActivity"
android:targetActivity=".wxapi.WXEntryActivity"
android:launchMode="singleTop">
<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
tools:replace="android:targetActivity"
android:name="${applicationId}.wxapi.WXPayEntryActivity"
android:exported="true"
android:targetActivity=".wxapi.WXPayEntryActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sdksample" />
</intent-filter>
</activity-alias>
```
### iOS
从1.0.0开始以下作废
~~在你的`AppDelegate`中重写下面方法~~:
```objective-c
- (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]];
}
```
如果你一定要重写这两个方法, 那么请确认你调用了`super`:
```
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [super application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
return [super application:application openURL:url options:options];
}
```
> 注意:为了能够返回你的app,请不要忘记添加URL Schema。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论