Keel — 5 first-class native modules for China
The most common pain point for domestic RN developers: WeChat / Alipay /
Amap / Jiguang / Umeng either don’t exist on Expo or have community
implementations with uneven quality. Keel maintains these 5 as
official first-class modules — install with one @keel-ai/<name> npm
line + standard autolink, no community piecing-together required.
This doc locks the spec: npm package names, JS surface, native implementation strategy, dependencies, limits.
General conventions
- Package name:
@keel-ai/<module>(official) orkeel-module-<name>(community); standard npm + autolink - JS surface: default export + flat methods; stay Promise-based + 1:1 mapped to the native SDK
- Native integration: iOS pulls in the official SDK via CocoaPods; Android via Maven
- Errors: all Promise rejects throw
KeelError(withcode: string+message), aligned with RN standard - Types: each
@keel-ai/<module>package ships.d.ts; editors get full autocomplete - Sample code: every module README contains a minimal demo
1. @keel-ai/wechat — WeChat Pay + Login + Share
Capabilities
| Feature | Method | Notes |
|---|---|---|
| Pay | pay(orderInfo) | Pulls up WeChat app for payment; returns { status, transactionId } |
| Sign-in | signIn() | OAuth code → exchange for access_token on your backend |
| Share | shareText / shareImage / shareLink / shareMiniProgram | Share to chat / moments / favorites |
| Open Mini Program | launchMiniProgram(appId, path) | Launch a WeChat mini program from your RN app |
Native dependencies
- iOS:
pod 'WechatOpenSDK_XCFramework'+ URL scheme config - Android:
implementation 'com.tencent.mm.opensdk:wechat-sdk-android'
Merchant requirements
- Must have a WeChat Open Platform account + mobile app appId
- Payment also requires a merchant ID (WeChat Pay mch_id) + API key
- Keel does NOT manage merchant credentials; users pass
appId+universalLink(iOS) on init
JS API (draft)
import { wechat } from '@keel-ai/wechat';
await wechat.init({ appId: 'wx...', universalLink: 'https://...' });
// Pay
const result = await wechat.pay({
partnerId: 'merchant ID',
prepayId: 'prepay_id returned by backend pre-order',
nonceStr: '...',
timestamp: ...,
package: 'Sign=WXPay',
sign: '...',
});
// Sign-in
const { code } = await wechat.signIn({ scope: 'snsapi_userinfo' });
// Use code to exchange for a token via your own backend
Limitations
- The WeChat SDK must be called on the main thread —
@keel-ai/wechatwraps this internally; callers don’t worry - On Android, the app signing fingerprint must match what’s registered
on the Open Platform — Keel CLI
keel doctorverifies
2. @keel-ai/alipay — Alipay Pay + Real-name auth + Mini Program
Capabilities
| Feature | Method | Notes |
|---|---|---|
| Pay | pay(orderString) | Pulls up Alipay app for payment |
| Real-name auth | realName(certifyId) | Ant Financial Cloud face verification |
| Launch Mini Program | launchMiniProgram(appId) | Open an Alipay mini program |
| Auth login | signIn(authInfo) | Get auth_code → exchange for user_id on backend |
Native dependencies
- iOS:
pod 'AlipaySDK-iOS' - Android:
implementation 'com.alipay.sdk:alipaysdk-android'
Merchant requirements
- Alipay Open Platform + app appId
- Payment requires an RSA2 key pair (public key uploaded to Alipay, private key held by backend)
- Same as WeChat — Keel does NOT manage credentials
JS API (draft)
import { alipay } from '@keel-ai/alipay';
const orderString = '<orderString assembled by backend>';
const result = await alipay.pay(orderString);
// result: { resultStatus: '9000' | '6001' | ..., result: '...' }
3. @keel-ai/amap — Amap (Gaode) maps + location + routing + geo
Capabilities
| Feature | Method / Component | Notes |
|---|---|---|
| Map component | <AMapView /> | RN component, renders the native map |
| Location | getCurrentLocation() / watchLocation(cb) | GPS + network hybrid positioning |
| Geocoding | geocode(address) / reverseGeocode(lat, lng) | Address ↔ coordinates |
| Routing | routePlan({ origin, dest, mode }) | Walking / cycling / driving / transit |
| POI search | searchPOI(keyword, region) | Search restaurants / gas stations etc. |
| Distance | distance(p1, p2) | Straight-line distance |
Native dependencies
- iOS:
pod 'AMap3DMap'+pod 'AMapLocation'+pod 'AMapSearch' - Android:
implementation 'com.amap.api:3dmap'+'location'+'search'
App keys
- Apply on the Amap open platform for a web-service key + iOS / Android client keys (each platform has its own key)
init({ iosKey, androidKey, webServiceKey })— Keel CLI reads fromkeel.json
JS API (draft)
import { amap, AMapView } from '@keel-ai/amap';
await amap.init({ iosKey, androidKey, webServiceKey });
// Component usage
<AMapView
style={{ flex: 1 }}
center={{ lat: 39.91, lng: 116.39 }}
zoom={14}
markers={[{ position: ..., title: ... }]}
/>;
// Imperative API
const loc = await amap.getCurrentLocation({ accuracy: 'high' });
const route = await amap.routePlan({ origin: loc, dest: ..., mode: 'driving' });
Alternatives
China also has Baidu Maps / Tencent Maps; by market share (maps: Baidu + Amap take ~90%), making one first-class is enough. Baidu users go through community modules (not Keel first-class).
4. @keel-ai/push — Push notifications (Jiguang + Getui dual backend)
Abstract layer + two backends
@keel-ai/push is an abstract interface with two native backends below:
@keel-ai/push ← abstract interface (small, ~300 LoC)
│
├─→ @keel-ai/push-jpush ← Jiguang backend (planned)
└─→ @keel-ai/push-getui ← Getui backend (planned)
Users pick one at init time and don’t run both simultaneously — to avoid double notifications across vendor channels.
import { push } from '@keel-ai/push';
await push.init({ provider: 'jpush', appKey: '...' }); // or 'getui'
const id = await push.register();
await push.setAlias('user_123');
Why not just Jiguang
- Jiguang: works out of the box; the free tier suits small/medium developers; auto-adapts to Huawei / Xiaomi / OPPO / vivo / FCM vendor channels; default backend
- Getui: more stable performance, enterprise SLA, long-link heartbeat more battery-friendly; choice for enterprise users
- Vendor direct integration (Huawei / Xiaomi / OPPO / vivo each): 5× the work; only top apps willing to do it; out of scope for now
Capabilities
| Feature | Method | Notes |
|---|---|---|
| Register | register() | Get registrationId (push target) |
| Set alias / tag | setAlias(alias) / addTags([...]) | Server pushes by alias / tag |
| Listen for notifications | onNotificationOpened(cb) / onMessageReceived(cb) | Different callbacks for in-app / app-closed cases |
| Badge | setBadge(num) | iOS badge |
| Clear notifications | clearAllNotifications() | Clears the notification center |
Native dependencies
- iOS:
pod 'JPush' - Android:
implementation 'cn.jiguang.sdk:jpush' - Vendor channels (auto-managed by Jiguang): Huawei / Xiaomi / OPPO / vivo / FCM each
App keys
Apply on the Jiguang Portal for AppKey + Master Secret (backend uses
the latter). Keel CLI configures appKey in keel.json.
JS API (draft)
import { jpush } from '@keel-ai/jpush';
await jpush.init({ appKey: '...', isProduction: true });
const id = await jpush.register(); // Backend records the registrationId
await jpush.setAlias('user_123');
jpush.onNotificationOpened((noti) => {
// User tapped a notification; handle the deep link
});
Limitations
- iOS APNs cert / p8 key must be uploaded to the Jiguang Portal
(one-time; Keel provides
doctorverification) - Android push permission requires explicit grant on OS 13+; the Keel SDK auto-prompts
5. @keel-ai/umeng — Umeng analytics + backup push
Capabilities
| Feature | Method | Notes |
|---|---|---|
| Track event | track(event, props) | Custom events + dimensions |
| Page tracking | pageEnter(name) / pageLeave(name) | RN screen transitions |
| User identity | signIn(userId) / signOut() | Associate users |
| Crash | reportCrash(error) | JS Error → Umeng crash report |
| Backup push | pushReceiver(handler) | Backup channel when Jiguang / Getui aren’t installed |
Native dependencies
- iOS:
pod 'UMCommon'+'UMAnalytics'+'UMCrash'(push:'UMPush') - Android:
implementation 'com.umeng.umsdk:common'+ per-module
App keys
Apply on Umeng console for AppKey + Channel ID (distinguishes app store of origin). Configured via Keel CLI.
JS API (draft)
import { umeng } from '@keel-ai/umeng';
await umeng.init({ appKey: '...', channel: 'Huawei' });
umeng.track('button_clicked', { button_id: 'pay' });
Why not Sentry / Firebase Analytics
- Sentry has unstable access from mainland China; self-reporting to Mortar works, but per-device analytics requires writing your own
- Firebase Analytics isn’t distributed in mainland China Google Play; reach on domestic Android devices is extremely low
- Umeng has native China presence; most domestic ops / ad-platforms natively support Umeng data callbacks
Domestic libraries NOT in the first-class set
| Library | Status | Recommended alternative |
|---|---|---|
| Tencent Maps | Community | Use @keel-ai/amap (Amap) |
| Baidu Maps | Community | Same as above |
| Getui | Community | Use @keel-ai/push (Jiguang backend) |
| Bugly Crash | Community | Use @keel-ai/umeng |
| Aliyun Sophix hotfix | Project-integrated | Use KAS Update |
| Meituan ACE container | Forbidden | Overlaps with Keel scope; not recommended |
Users needing these community modules pull them in via standard npm; Keel doesn’t block but doesn’t officially support either.
Planned implementation order (by market demand + tech dependency)
@keel-ai/pushabstract layer + jpush backend — most-used + easiest (Jiguang SDK is mature); the abstract interface needs to be carefully designed up front (not locked to a single backend)- WeChat Pay — required for the business model
- Alipay — same
- Amap — required for LBS apps
- Umeng — required for data callbacks
@keel-ai/push-getuisecond backend — extra choice for enterprise users; deferred until after jpush ships and we see real feedback
Abstract layer + single backend ~3 weeks; second backend ~3 weeks (including native integration + server-side dispatcher). Each other module expected ~2-3 weeks dev + 1 week internal beta; total ~3-4 months coverage.
Coordination with Mortar
Keel’s 5 modules only handle client-side native integration. Server-side signature verification / callback handling / data persistence is Mortar’s job:
@keel-ai/wechat’s pay returnsprepayId; Mortarfeature/paymenthandles signing + state machine (planned)@keel-ai/jpush’s push trigger: Mortar backend calls the Jiguang server API (users don’t write their own backend code)@keel-ai/umeng’s crash reports can optionally forward to Mortarfeature/usagefor backup
This coordination makes Keel users also Mortar users — a bundled value proposition.