mp_flutter_wechat 0.3.2
mp_flutter_wechat: ^0.3.2 copied to clipboard
WeChat Mini Program APIs (login, payment, and more) for Flutter apps compiled with flutter_miniprogram; throws clear errors on other platforms.
mp_flutter_wechat #
WeChat native APIs (login, payment, and more) for Flutter apps compiled into
a WeChat Mini Program by mp-flutter (flutter_miniprogram
on pub.flutter-io.cn). On other platforms (Android/iOS/desktop, or a plain browser)
calling these APIs throws a clear error instead of failing silently.
中文版见 README.zh.md.
Install #
dependencies:
mp_flutter_wechat: ^0.3.2
When developing inside the mp-flutter monorepo itself (e.g. the top-level
example/ app), use a relative path dependency instead:
dependencies:
mp_flutter_wechat:
path: ../mp_flutter/packages/mp_flutter_wechat
See example/lib/main.dart in this package for a
minimal, runnable usage example.
API #
| Method | WeChat API | Notes |
|---|---|---|
MpWechat.isAvailable |
— | Whether the WeChat bridge (self.__mpWechat) exists in the current environment |
MpWechat.login() |
wx.login |
Returns a code; exchanging it for openid/session_key must happen on your server |
MpWechat.checkSession() |
wx.checkSession |
Whether the login session is still valid; returns false on failure instead of throwing |
MpWechat.requestPayment(params) |
wx.requestPayment |
params comes from your server's signed "unified order" response |
MpWechat.chooseAddress() |
wx.chooseAddress |
Opens the shipping-address picker |
MpWechat.scanCode({onlyFromCamera}) |
wx.scanCode |
Opens the QR/barcode scanner |
MpWechat.setClipboardData(data) |
wx.setClipboardData |
Writes to the clipboard |
MpWechat.getClipboardData() |
wx.getClipboardData |
Reads from the clipboard |
MpWechat.getLocation({type}) |
wx.getLocation |
Default coordinate system is gcj02 |
MpWechat.makePhoneCall(phoneNumber) |
wx.makePhoneCall |
Places a phone call |
MpWechat.setShareInfo({title, path, imageUrl, query}) |
— | Sets the share info used by the host page's onShareAppMessage |
MpWechat.menuButtonRect() |
wx.getMenuButtonBoundingClientRect |
Capsule button position, Future<Rect?> in logical pixels; null outside a Mini Program — see "Avoiding the capsule button" below |
MpWechat.call(api, [params]) |
any wx.* |
Generic escape hatch for APIs not wrapped above; only supports success/fail-callback-style async APIs — sync APIs (*Sync), event subscriptions (on*/off*), and factories/handles (create*, *Manager) throw immediately instead of hanging |
On non-Mini-Program platforms (the stub implementation) or on the Web when
the __mpWechat bridge is absent:
isAvailableisfalsecheckSession()returnsfalse(never throws)setShareInfo(...)is a no-op (never throws)- every other method (including
call) throwsUnsupportedError('mp_flutter_wechat: <api> is only available in a WeChat Mini Program compiled by mp-flutter')
Server-side responsibilities (sensitive operations) #
The following require an AppSecret or merchant key and must never live
on the client — they belong on your business server:
code2Session(WeChat docs:auth.code2Session): exchange thecodereturned bylogin()foropenid/unionid/session_key.- Unified order + signing (WeChat Pay docs: the unified-order API and the
Mini Program payment signing rules): produces the
timeStamp/nonceStr/package/signType/paySignrequired byrequestPayment().
Handling user cancellation #
Failures (including the user cancelling) throw MpWechatException, whose
cancelled field distinguishes "the user backed out" from other failures:
try {
await MpWechat.requestPayment(params);
} on MpWechatException catch (e) {
if (e.cancelled) {
// User cancelled the payment; returning silently is fine.
} else {
// A real failure — e.api / e.errMsg have the details.
showToast(e.errMsg);
}
}
Behavior outside a Mini Program #
On Android/iOS/desktop (the channel_stub.dart implementation) or in a
plain browser (no self.__mpWechat on the Web, so channel_web.dart reports
isAvailable == false), check MpWechat.isAvailable before deciding whether
to show WeChat-specific UI, so you never hit an UnsupportedError:
if (MpWechat.isAvailable) {
final code = await MpWechat.login();
// ...
}
Avoiding the capsule button #
Pages generated by mp-flutter render on a full-screen canvas
(navigationStyle: custom); the build step injects the Mini Program's safe
area (status bar/notch, bottom home indicator) into MediaQuery.padding/
viewPadding, so SafeArea, Scaffold, and AppBar already avoid those
regions without changes. The capsule button in the top-right corner is not
part of that padding (same as in native apps — padding only describes
space the system itself occupies).
When you need to place a button or text near the top-right without it being
covered by the capsule, use MpWechat.menuButtonRect() to get its rect and
leave room yourself:
final rect = await MpWechat.menuButtonRect(); // null outside a Mini Program
final width = MediaQuery.sizeOf(context).width;
final rightGap = rect == null ? 16.0 : width - rect.left + 8; // +8 past the capsule's left edge
Padding(padding: EdgeInsets.only(right: rightGap), child: header);
Share info example #
Each call to setShareInfo replaces the previously set share info
wholesale rather than merging field by field: a call that only passes
title clears any path/imageUrl/query set earlier, and the host
page's onShareAppMessage only sees the fields from the latest call. If
path is given and doesn't start with /, Dart throws ArgumentError
immediately (Mini Program page paths must start with /).
MpWechat.setShareInfo(
title: 'Limited-time offer',
path: '/pages/flutter/flutter?sku=1',
imageUrl: 'https://example.com/share.png',
);
Limitations #
- Only success/fail-callback-style
wx.*APIs are supported throughMpWechat.call. Synchronous APIs (*Sync), event subscriptions (on*/off*), and factory/handle-style APIs (create*,*Manager) are out of scope and throw immediately if called through this package. - This package only talks to the bridge; it does not perform any sensitive, secret-bearing operation itself (see "Server-side responsibilities" above).
- Behavior is only fully exercised inside a Mini Program compiled by
mp-flutter; other platforms get the documented stub/
UnsupportedErrorbehavior, not a WeChat API polyfill.
Implementation note: exception mapping on Web #
In lib/src/channel_web.dart, the JS bridge (wechat.js) rejects with an
Error carrying three custom properties: mpApi/mpErrMsg/mpCancelled.
Verified empirically (WeChat DevTools + dart2js output, the pay step of
accept-wx.js): dart2js hands the rejected JS Error to Dart's catch
unchanged, and e is JSObject holds — there's no need to switch to
JSPromise.then(onFulfilled, onRejected) to receive the raw rejection value.
Even so, the catch block only maps to MpWechatException when the object
actually carries mpErrMsg/mpApi (i.e. it really came from wechat.js's
fail()); otherwise it rethrows unchanged. Extension-type casts are
unchecked, so any JSObject can be cast to the internal bridge-error type
without error — missing fields just come back null. Without this check,
any rejected JS value would be treated as an MpWechatException, masking
real bugs.