wechat_kit 1.0.3

  • Readme
  • Changelog
  • Example
  • Installing
  • 86

wechat_kit #

Build Status Codecov GitHub Tag Pub Package License

flutter版微信SDK

flutter toolkit #

dart/flutter 私服 #

docs #

android #

# 不需要做任何额外接入工作
# 混淆已打入 Library,随 Library 引用,自动添加到 apk 打包混淆
<manifest>
    <!-- targetSdkVersion >= 29 && compileSdkVersion >= 29, 豁免 Android Q 的外部存储沙箱限制 -->
    <application android:requestLegacyExternalStorage="true">
    </application>
</manifest>

获取 android 微信签名信息

非官方方法 -> 反编译 Gen_Signature_Android2.apk 所得

命令:

keytool -list -v -keystore ${your_keystore_path} -storepass ${your_keystore_password} 2>/dev/null | grep -p 'MD5:.*' -o | sed 's/MD5://' | sed 's/ //g' | sed 's/://g' | awk '{print tolower($0)}'

示例:

keytool -list -v -keystore example/android/app/infos/dev.jks -storepass 123456 2>/dev/null | grep -p 'MD5:.*' -o | sed 's/MD5://' | sed 's/ //g' | sed 's/://g' | awk '{print tolower($0)}'
28424130a4416d519e00946651d53a46

ios #

在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id

URL Types
weixin: identifier=weixin schemes=${appId}
iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>weixin</string>
    <string>weixinULAPI</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
Universal Links

Capabilities -> Associated Domain -> Domain -> applinks:${your applinks}

flutter #

  • snapshot
dependencies:
  wechat_kit:
    git:
      url: https://github.com/v7lin/fake_wechat.git
  • release
dependencies:
  wechat_kit: ^${latestTag}
  • example

示例

Getting Started #

This project is a starting point for a Flutter plug-in package, a specialized package that includes platform-specific implementation code for Android and/or iOS.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

1.0.3 - 2019.2.25 #

  • scope: String -> List

1.0.2 - 2019.2.10 #

  • 添加方法

1.0.1 - 2019.12.05 #

  • 修正 homepage
  • 适配 Android Q 本地分享(targetSdkVersion >= 29,豁免外部存储沙箱限制,微信SDK并没有提供 FileProvider 方式)
  • 修正小程序分享(by Ycong

1.0.0 - 2019.12.02 #

  • 更名 wechat_kit
  • 添加 Android 代码静态检查

0.3.4 - 2019.9.25 #

  • 升级Android/iOS SDK
  • 修正 Universal Links 文档(by kenleemyth

0.3.3 - 2019.8.8 #

  • 升级Android SDK
  • 修正二维码扫码登录

0.3.2 - 2019.7.12 #

  • 简化

0.3.1 - 2019.6.5 #

  • 添加小图字节数组分享

0.3.0 - 2019.5.24 #

  • 优化
  • 自动化发布

0.2.0 - 2019.4.26 #

  • 修正大图分享
  • 添加表情/GIF分享

0.1.0 - 2019.3.19 #

  • 规范 library 代码

0.0.1 - 2019.3.4 #

  • android/ios wechat

example/lib/main.dart

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:image/image.dart' as image;
import 'package:okhttp_kit/okhttp_kit.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as path_provider;
import 'package:wechat_kit/wechat_kit.dart';

void main() => runApp(MyApp());

const String WECHAT_APPID = 'wx854345270316ce6e';
const String WECHAT_UNIVERSAL_LINK = null; // iOS 请配置
const String WECHAT_APPSECRET = 'ce4c6c4f007cf10baad3f600da16aa8e';
const String WECHAT_MINIAPPID = 'gh_wxd930ea5d5a258f4f';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeState();
  }
}

class _HomeState extends State<Home> {
  Wechat _wechat = Wechat()
    ..registerApp(
      appId: WECHAT_APPID,
      universalLink: WECHAT_UNIVERSAL_LINK,
    );

  StreamSubscription<WechatAuthResp> _auth;
  StreamSubscription<WechatSdkResp> _share;
  StreamSubscription<WechatPayResp> _pay;
  StreamSubscription<WechatLaunchMiniProgramResp> _miniProgram;

  WechatAuthResp _authResp;

  @override
  void initState() {
    super.initState();
    _auth = _wechat.authResp().listen(_listenAuth);
    _share = _wechat.shareMsgResp().listen(_listenShareMsg);
    _pay = _wechat.payResp().listen(_listenPay);
    _miniProgram = _wechat.launchMiniProgramResp().listen(_listenMiniProgram);
  }

  void _listenAuth(WechatAuthResp resp) {
    _authResp = resp;
    String content = 'auth: ${resp.errorCode} ${resp.errorMsg}';
    _showTips('登录', content);
  }

  void _listenShareMsg(WechatSdkResp resp) {
    String content = 'share: ${resp.errorCode} ${resp.errorMsg}';
    _showTips('分享', content);
  }

  void _listenPay(WechatPayResp resp) {
    String content = 'pay: ${resp.errorCode} ${resp.errorMsg}';
    _showTips('支付', content);
  }

  void _listenMiniProgram(WechatLaunchMiniProgramResp resp) {
    String content = 'mini program: ${resp.errorCode} ${resp.errorMsg}';
    _showTips('拉起小程序', content);
  }

  @override
  void dispose() {
    if (_auth != null) {
      _auth.cancel();
    }
    if (_share != null) {
      _share.cancel();
    }
    if (_pay != null) {
      _pay.cancel();
    }
    if (_miniProgram != null) {
      _miniProgram.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('WechatKit Demo'),
      ),
      body: ListView(
        children: <Widget>[
          ListTile(
            title: const Text('环境检查'),
            onTap: () async {
              String content =
                  'wechat: ${await _wechat.isInstalled()} - ${await _wechat.isSupportApi()}';
              _showTips('环境检查', content);
            },
          ),
          ListTile(
            title: const Text('登录'),
            onTap: () {
              _wechat.auth(
                scope: <String>[WechatScope.SNSAPI_USERINFO],
                state: 'auth',
              );
            },
          ),
          ListTile(
            title: const Text('扫码登录'),
            onTap: () {
              Navigator.of(context).push(MaterialPageRoute<dynamic>(
                builder: (BuildContext context) => Qrauth(
                  wechat: _wechat,
                ),
              ));
              ;
            },
          ),
          ListTile(
            title: const Text('获取用户信息'),
            onTap: () {
              if (_authResp != null &&
                  _authResp.errorCode == WechatSdkResp.ERRORCODE_SUCCESS) {
                _wechat
                    .getAccessTokenUnionID(
                  appId: WECHAT_APPID,
                  appSecret: WECHAT_APPSECRET,
                  code: _authResp.code,
                )
                    .then((WechatAccessTokenResp accessTokenResp) {
                  if (accessTokenResp.errcode ==
                      WechatApiResp.ERRORCODE_SUCCESS) {
                    _wechat
                        .getUserInfoUnionID(
                      openId: accessTokenResp.openid,
                      accessToken: accessTokenResp.accessToken,
                    )
                        .then((WechatUserInfoResp userInfoResp) {
                      if (userInfoResp.errcode ==
                          WechatApiResp.ERRORCODE_SUCCESS) {
                        _showTips('用户信息',
                            '${userInfoResp.nickname} - ${userInfoResp.sex}');
                      }
                    });
                  }
                });
              }
            },
          ),
          ListTile(
            title: const Text('文字分享'),
            onTap: () {
              _wechat.shareText(
                scene: WechatScene.TIMELINE,
                text: 'Share Text',
              );
            },
          ),
          ListTile(
            title: const Text('图片分享'),
            onTap: () async {
              OkHttpClient client = OkHttpClientBuilder().build();
              Response resp = await client
                  .newCall(RequestBuilder()
                      .get()
                      .url(HttpUrl.parse(
                          'https://www.baidu.com/img/bd_logo1.png?where=super'))
                      .build())
                  .enqueue();
              if (resp.isSuccessful()) {
                Directory saveDir = Platform.isAndroid
                    ? await path_provider.getExternalStorageDirectory()
                    : await path_provider.getApplicationDocumentsDirectory();
                File saveFile = File(path.join(saveDir.path, 'timg.png'));
                if (!saveFile.existsSync()) {
                  saveFile.createSync(recursive: true);
                  saveFile.writeAsBytesSync(
                    await resp.body().bytes(),
                    flush: true,
                  );
                }
                await _wechat.shareImage(
                  scene: WechatScene.SESSION,
                  imageUri: Uri.file(saveFile.path),
                );
              }
            },
          ),
          ListTile(
            title: const Text('Emoji分享'),
            onTap: () async {
              OkHttpClient client = OkHttpClientBuilder().build();
              Response resp = await client
                  .newCall(RequestBuilder()
                      .get()
                      .url(HttpUrl.parse(
                          'https://n.sinaimg.cn/tech/transform/695/w467h228/20191119/bf27-iipztfe9404360.gif'))
                      .build())
                  .enqueue();
              if (resp.isSuccessful()) {
                Directory saveDir = Platform.isAndroid
                    ? await path_provider.getExternalStorageDirectory()
                    : await path_provider.getApplicationDocumentsDirectory();
                File saveFile = File(path.join(saveDir.path, 'timg.gif'));
                if (!saveFile.existsSync()) {
                  saveFile.createSync(recursive: true);
                  saveFile.writeAsBytesSync(
                    await resp.body().bytes(),
                    flush: true,
                  );
                }
                image.Image thumbnail =
                    image.decodeGif(saveFile.readAsBytesSync());
                Uint8List thumbData = thumbnail.getBytes();
                if (thumbData.length > 32 * 1024) {
                  thumbData = Uint8List.fromList(image.encodeJpg(thumbnail,
                      quality: 100 * 32 * 1024 ~/ thumbData.length));
                }
                await _wechat.shareEmoji(
                  scene: WechatScene.SESSION,
                  thumbData: thumbData,
                  emojiUri: Uri.file(saveFile.path),
                );
              }
            },
          ),
          ListTile(
            title: const Text('网页分享'),
            onTap: () {
              _wechat.shareWebpage(
                scene: WechatScene.TIMELINE,
                webpageUrl: 'https://www.baidu.com',
              );
            },
          ),
          ListTile(
            title: const Text('支付'),
            onTap: () {
              // 微信 Demo 例子:https://wxpay.wxutil.com/pub_v2/app/app_pay.php
              _wechat.pay(
                appId: WECHAT_APPID,
                partnerId: '商户号',
                prepayId: '预支付交易会话ID',
                package: '扩展字段,暂填写固定值:Sign=WXPay',
                nonceStr: '随机字符串, 随机字符串,不长于32位',
                timeStamp: '时间戳:东八区,单位秒',
                sign: '签名',
              );
            },
          ),
          ListTile(
            title: const Text('拉起小程序'),
            onTap: () {
              _wechat.launchMiniProgram(
                userName: WECHAT_MINIAPPID,
                path: "page/page/index?uid=123",
                type: WechatMiniProgram.preview,
              );
            },
          ),
        ],
      ),
    );
  }

  void _showTips(String title, String content) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(title),
          content: Text(content),
        );
      },
    );
  }
}

class Qrauth extends StatefulWidget {
  const Qrauth({
    Key key,
    this.wechat,
  }) : super(key: key);

  final Wechat wechat;

  @override
  State<StatefulWidget> createState() {
    return _QrauthState();
  }
}

class _QrauthState extends State<Qrauth> {
  StreamSubscription<Uint8List> _authGotQrcode;
  StreamSubscription<String> _authQrcodeScanned;
  StreamSubscription<WechatQrauthResp> _authFinish;

  Uint8List _qrcod;

  @override
  void initState() {
    super.initState();
    _authGotQrcode =
        widget.wechat.authGotQrcodeResp().listen(_listenAuthGotQrcode);
    _authQrcodeScanned =
        widget.wechat.authQrcodeScannedResp().listen(_listenAuthQrcodeScanned);
    _authFinish = widget.wechat.authFinishResp().listen(_listenAuthFinish);
  }

  void _listenAuthGotQrcode(Uint8List qrcode) {
    _qrcod = qrcode;
    setState(() {});
  }

  void _listenAuthQrcodeScanned(String msg) {
    print('msg: $msg');
  }

  void _listenAuthFinish(WechatQrauthResp qrauthResp) {
    print('resp: ${qrauthResp.errorCode} - ${qrauthResp.authCode}');
  }

  @override
  void dispose() {
    if (_authGotQrcode != null) {
      _authGotQrcode.cancel();
    }
    if (_authQrcodeScanned != null) {
      _authQrcodeScanned.cancel();
    }
    if (_authFinish != null) {
      _authFinish.cancel();
    }
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Qrauth'),
        actions: <Widget>[
          FlatButton(
            onPressed: () async {
              WechatAccessTokenResp accessToken =
                  await widget.wechat.getAccessToken(
                appId: WECHAT_APPID,
                appSecret: WECHAT_APPSECRET,
              );
              print(
                  'accessToken: ${accessToken.errcode} - ${accessToken.errmsg} - ${accessToken.accessToken}');
              WechatTicketResp ticket = await widget.wechat.getTicket(
                accessToken: accessToken.accessToken,
              );
              print(
                  'accessToken: ${ticket.errcode} - ${ticket.errmsg} - ${ticket.ticket}');
              await widget.wechat.startQrauth(
                appId: WECHAT_APPID,
                scope: <String>[WechatScope.SNSAPI_USERINFO],
                ticket: ticket.ticket,
              );
            },
            child: const Text('got qr code'),
          ),
        ],
      ),
      body: GestureDetector(
        child: Center(
          child:
              _qrcod != null ? Image.memory(_qrcod) : const Text('got qr code'),
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  wechat_kit: ^1.0.3

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:wechat_kit/wechat_kit.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
72
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
86
Learn more about scoring.

We analyzed this package on Jul 2, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.8.4
  • pana: 0.13.9+1
  • Flutter: 1.17.3

Analysis suggestions

Package does not support Flutter platform linux

Because of import path [package:wechat_kit/wechat_kit.dart]

Package does not support Flutter platform macos

Because of import path [package:wechat_kit/wechat_kit.dart]

Package does not support Flutter platform web

Because of import path [package:wechat_kit/wechat_kit.dart]

Package does not support Flutter platform windows

Because of import path [package:wechat_kit/wechat_kit.dart]

Package not compatible with SDK dart

because of import path [wechat_kit]

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
convert ^2.0.2 2.1.1
crypto ^2.0.6 2.1.5
flutter 0.0.0
json_annotation >=2.0.0 <4.0.0 3.0.1
uuid >=1.0.0 <3.0.0 2.1.0
Transitive dependencies
charcode 1.1.3
collection 1.14.12 1.14.13
meta 1.1.8 1.2.0
sky_engine 0.0.99
typed_data 1.1.6 1.2.0
vector_math 2.0.8
Dev dependencies
build_runner any
flutter_test
image ^2.0.7
json_serializable any
okhttp_kit ^1.0.0
path ^1.6.4
path_provider ^1.4.0
pedantic any