keel-module-wechat
v0.1.0
Published
微信登录 (WeChat OAuth sign-in) for Keel React Native apps.
Maintainers
Readme
keel-module-wechat
微信登录 (WeChat OAuth sign-in) for Keel apps — the reference Keel vendor module wrapping a callback-driven, app-switching SDK.
login() runs the snsapi_userinfo OAuth flow: it switches to the WeChat
app, the user taps 确认登录, control returns to your app, and you get a
one-time code. Your server exchanges that code (with the app secret)
for an access_token + openid — the secret never ships in the bundle.
| Platform | Upstream SDK | Symbol |
|----------|--------------|--------|
| iOS | WeChat Open SDK xcframework — wired as an SPM .binaryTarget in Package.swift (Tencent's official CDN zip, pinned by checksum) | WXApi / SendAuthReq |
| Android | com.tencent.mm.opensdk:wechat-sdk-android (maven) | IWXAPI / SendAuth.Req |
iOS delivery note (verified on a real keel-go build): an SPM source target can't
importa CocoaPods module, so the upstream SDK is consumed as an SPM.binaryTarget(notios.pods/Podfile) — that keeps the@KeelModulemacro AND lets the wrapper seeWechatOpenSDK. The SDK's transitive system frameworks (WebKit/Security/z/sqlite3/c++…) are declared aslinkerSettingsinPackage.swift(CocoaPods adds these automatically; SPM does not). Bumping the SDK = update the binaryTarget url + checksum (swift package compute-checksum) and re-sync linkerSettings with the pod'sframeworks/libraries.
Install
keel install keel-module-wechatLinking is automatic via Keel autolinking (no manual Podfile/Gradle edits):
- iOS —
keel-module autolink --emit=spmdiscoversmodule.ymland adds theKeelModuleWechatSPM target to the hostproject.yml; the hostKeelModulesProvider.registerAll()registers it. - Android —
keel-module autolink --emit=gradleincludes the AAR and the generatedKeelModulesProviderregisters it.
You still do the WeChat-specific host wiring below (every WeChat integration needs it — the callback can't reach JS otherwise).
Usage
import * as wechat from 'keel-module-wechat';
// 1. Once, at app launch:
await wechat.register({
appId: 'wx1234567890abcdef',
universalLink: 'https://app.example.com/wx/', // iOS only; see below
});
// 2. Gate the button:
if (await wechat.isWeChatInstalled()) {
// 3. Run the flow:
const { code, state } = await wechat.login({ state: 'csrf-nonce' });
// 4. POST `code` to YOUR server → it calls WeChat's oauth2/access_token
// with the app secret and returns your own session.
}login() rejects on user cancel (login cancelled), denial
(login denied), or if WeChat isn't installed.
Host integration
You need a 移动应用 AppID from https://open.weixin.qq.com (开放平台 → 管理中心 → 移动应用). Register your iOS Universal Link / Bundle ID and Android package name + signing signature there, or WeChat refuses the callback.
iOS
SDK — already wired via the SPM
.binaryTargetinPackage.swift(no host action).isSupported()returnstrueonce the module is in the build.URL scheme — add
wx<your-appid>to the app'sCFBundleURLTypes.Query schemes — add
weixin,weixinULAPI,weixinURLParamsAPItoLSApplicationQueriesSchemes(soisWeChatInstalled()works on iOS 9+).Universal Link — host an
apple-app-site-associationat theuniversalLinkdomain and pass that URL toregister(). WeChat 7.0.13+ requires it to return to your app.Route the callback to the module. In a SwiftUI host's
SceneDelegate(keel-go uses one already) and/orAppDelegate:import KeelModuleWechat // UISceneDelegate (custom-scheme return): func scene(_ scene: UIScene, openURLContexts contexts: Set<UIOpenURLContext>) { if let url = contexts.first?.url, KeelModuleWechat.handleOpen(url) { return } // … existing keel:// handling … } // Universal-Link return: func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { _ = KeelModuleWechat.handleOpenUniversalLink(userActivity) }(UIKit
AppDelegatehosts call the same two static methods fromapplication(_:open:options:)andapplication(_:continue:restorationHandler:).)
Android
The SDK is pulled automatically (
build.gradle.ktsdeclarescom.tencent.mm.opensdk:wechat-sdk-android).<queries>— soisWeChatInstalled()works on Android 11+, add toAndroidManifest.xml:<queries><package android:name="com.tencent.mm" /></queries>WXEntryActivity — WeChat dispatches the callback to a class at the fixed path
${applicationId}.wxapi.WXEntryActivity, so it must live in the host app. Create<your.package>/wxapi/WXEntryActivity.kt— a 6-line forwarder into this module (keel-go:com.keel.go.wxapi):package com.keel.go.wxapi // == ${applicationId}.wxapi import android.app.Activity import android.content.Intent import android.os.Bundle import com.keel.modules.keelModuleWechat.KeelModuleWechatModule class WXEntryActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) KeelModuleWechatModule.handleIntent(intent) finish() } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) KeelModuleWechatModule.handleIntent(intent) finish() } }Declare it
exported+taskAffinityin the manifest:<activity android:name=".wxapi.WXEntryActivity" android:exported="true" android:taskAffinity="${applicationId}" android:launchMode="singleTask" />
Server side
login() returns only a code. Your backend exchanges it:
GET https://api.weixin.qq.com/sns/oauth2/access_token
?appid=<AppID>&secret=<AppSecret>&code=<code>&grant_type=authorization_codeKeep <AppSecret> on the server. Verify the state you passed matches.
Development
keel-module validate # check module.yml against actual source pathsLicense
Apache-2.0 — see LICENSE in the parent monorepo.
