概述
在SuperApp實踐時,對於小程式的管理和使用,使用者一般會使用到以下幾個情境:
搜尋
推薦
收藏
最近使用
方案介紹
用戶端搜尋/全量拉取小程式
推薦位
情境描述:
對於SuperApp一般會有固定的小程式推薦展位,方便對特定小程式進行引流。
方案描述:
SuperApp需要自己實現推薦展位的邏輯,但是在展位管理服務中,可以接入應用開放平台的API用於尋找線上的應用。

API:
接入展位管理服務,請參見SuperApp 管理介面的小程式管理時查詢介面和小程式中繼資料查詢介面。
收藏
情境描述:
使用者通過收藏小程式快速開啟某些小程式。
方案描述:
使用者需要在容器配置中開啟收藏服務開關,並且實現小程式收藏的用戶端SPI。

API:
用戶端接入,請參見用戶端介面的收藏。
服務端接入,請參見SuperApp 管理介面的小程式中繼資料查詢介面。
最近使用
情境描述:
使用者需要擷取最近使用的小程式。
方案描述:
使用者需要接入容器小程式開啟事件SPI。

API:
用戶端接入,請參見用戶端介面的最近使用。
服務端接入,請參見SuperApp 管理介面的小程式中繼資料查詢介面。
介面概覽
SuperApp 管理介面
SuperApp 管理介面是面向 SuperApp 提供的後端介面,使用目標 APP 的 accessKey / secretKey 進行鑒權。
逐頁查詢線上小程式列表
介面名:
/openapi/v1/channel/miniapp/searchMethod: POST
Content-Type: application/json
Body:
{ "after": "0", # 遊標,第一頁從"0"開始,下一頁的起始位置參考返回結果中的"after"欄位。 "limit": 10, # 查詢數量 "keyWord": "demo" # 查詢關鍵字 }Response
{ "success":true, "model":{ "after":"64",# 下一頁的起始位置,如果該值等於"-1"表示查詢結束。 "size":2, "data":[ { "id":390, "appId":"1511654371932651552768", "miniappCode":"1511654371932651552768", "publishServicePlanId":"P442675078547163136", "name":"uniapp-hll-0505", "version":"1.0.1", "description":"", "slogan":"11111", "platform":"MiniApp", "framework":"UniApp", "icon":"icon/app/50112037081b4d5e9955f43aae22fb0d.jpeg", "publicIcon":"https://ceph-pre1.emas-poc.com/emas-cdn/publish/intercnn/icon/app/50112037081b4d5e9955f43aae22fb0d.jpeg" }, { "id":64, "appId":"1511608276458218872832", "miniappCode":"1511608276458218872832", "publishServicePlanId":"P396236781277202432", "name":"HllwindVane1129", "version":"0.0.2", "description":"", "slogan":"", "platform":"MiniApp", "framework":"WindVane", "icon":"icon/app/b4d6ff4f9111470c95f4ac2ef1c3079d.jpeg", "publicIcon":"http://cxfe-daily.oss-cn-hangzhou.aliyuncs.com/icon/app/b4d6ff4f9111470c95f4ac2ef1c3079d.jpeg?Expires=1672281817&OSSAccessKeyId=xxx&Signature=ZpoXL%2Bo4UGHAcgIQTMPQc30sQ1c%3D" } ] } }
發行小程式元資訊查詢
介面名:
/openapi/v1/channel/miniappMethod: POST
Content-Type: application/json
Body:
{ "miniappCode": "1511654371932651552768" }Response:
{ "success":true, "model":{ "channelCode":"1611606158604452241408", "gmtCreate":1683268112168, "gmtModified":1683350460819, "description":{ "inuseStatus":"ACTIVE", "description":"", "icon":"icon/app/50112037081b4d5e9955f43aae22fb0d.jpeg", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/app/50112037081b4d5e9955f43aae22fb0d.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T092821Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=094773e26ff4ab9ec84e091367670ac007e9b43208bce59fbadd2bece7a3cc46" }, "platform":"MiniApp", "framework":"UniApp", "publishStatus":"ONLINE", "onlineVersion":"1.0.1" } }
目標 APP 類目查詢
Path:
/openapi/v1/channel/category/listMethod: POST
Content-Type: application/json
Header: x-locale: zh_CN(中文)/ en_US(英文, 預設)
body:
{}response
{ "success":true, "model":[ { "name":"Bills", "channelCode":"1611606158604452241408", "categoryId":1, "status":"ENABLE", "sort":0, "gmtCreate":1690366685363, "gmtModified":1690366685363 }, { "name":"Food & Beverage", "channelCode":"1611606158604452241408", "categoryId":3, "status":"ENABLE", "sort":1, "gmtCreate":1690366685365, "gmtModified":1690366685365 } ] }
目標 APP 類目綁定小程式查詢
Path:
/openapi/v1/channel/category/miniapp/listMethod: POST
Content-Type: application/json
body:
{ "categoryId": 1L }response
{ "success":true, "model":[ { "name":"三方-uniapp", "icon":"icon/channel/default_miniapp_icon.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/default_miniapp_icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T094401Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=e515ba8ade8f66d0473c8c407b5a9b90385f5e6cba1a2b9e885232f3a6969020", "channelCode":"1611606158604452241408", "categoryId":3, "miniappCode":"1511686301389817548800", "channelTagName":"HOTHOTHOTHOTHOTHOTHOTHOTHOT", "publishStatus":"ONLINE", "onlineVersion":"0.0.1", "sort":0, "gmtCreate":1690882000531, "gmtModified":1690882032947 } ] }
管理介面簽名方式
Request Header
要求標頭主要包含以下幾個Fields
Header | Required | Description | Code sample |
X-Request-Sign | Yes | 本次請求產生的簽名,預設為HmacSHA1。 | X-Request-Sign:**** |
X-Access-Key | Yes | 請求方的身份識別ID,AccessKey。 | X-Access-Key:APP的AccessKey。 |
X-Request-Timestamp | Yes | 時間戳記 | X-Timestamp:時間戳記。 |
Content-Type | No | 內容格式 | Content-Type: application/json; charset=UTF-8 |
首先在SuperApp開放平台擷取APP的accessKey和secretKey。每次請求都會有以下屬性:
HTTP_URI : 例如
/openapi/v1/channel/miniapp/searchX-Access-Key:46b1cac78ed94ca4b99ad6de550a****
X-Request-Timestamp:1676904384074
HTTP_BODY : body 舉例如下:
{ "after": "0", # 遊標,第一頁從"0"開始,下一頁的起始位置參考返回結果中的"after"欄位。 "limit": 10, # 查詢數量 "keyWord": "demo" # 查詢關鍵字 }
基於以上資訊,
{Content_To_Be_Signed}的格式如下,我們可以構造出需要加簽的content。<HTTP_METHOD> <HTTP_URI>\n<HTTP_BODY>.<Request-Time>.<Access-Key>POST /openapi/v1/channel/miniapp/search { "after": "0", "limit": 10, "keyWord": "demo" }.1676904384074.46b1cac78ed94ca4b99ad6de550a****使用HmacSHA1演算法,以下的程式碼範例展示了如何加簽一個請求。
import org.apache.commons.lang3.StringUtils; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Base64; public class SignDemo { private static final char[] HEX = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; public static String sign(String requestURI, String accessKey, String secretKey, Long requestTime, String requestBody) { String content = String.format("POST %s\n%s.%s.%s", requestURI, requestBody, requestTime, accessKey); String signed = generateSign(content, secretKey, "HmacSHA1"); return Base64.getEncoder().encodeToString(signed.getBytes(StandardCharsets.UTF_8)); } public static String generateSign(String content, String key, String algorithm) { if (!StringUtils.isEmpty(algorithm) && !StringUtils.isEmpty(content) && null != key) { try { SecretKeySpec signinKey = new SecretKeySpec(key.getBytes(), algorithm); Mac mac = Mac.getInstance(algorithm); mac.init(signinKey); byte[] rawHmac = mac.doFinal(content.getBytes()); return convertToHex(rawHmac); } catch (InvalidKeyException | NoSuchAlgorithmException var6) { return ""; } } else { return ""; } } public static String convertToHex(byte[] bytes) { int len = bytes.length; StringBuilder buf = new StringBuilder(len * 2); for (int j = 0; j < len; ++j) { buf.append(HEX[bytes[j] >> 4 & 15]); buf.append(HEX[bytes[j] & 15]); } return buf.toString(); } }發送請求
通過將X-Access-Key、X-Request-Timestamp和X-Request-Sign添加到要求標頭,可以構造出如下請求:
curl -X POST \
https://example.com/openapi/v1/channel/miniapp/search \
-H 'Content-Type: application/json' \
-H 'X-Access-Key: 46b1cac78ed94ca4b99ad6de550afb68' \
-H 'X-Request-Timestamp: 1676904384074' \
-H 'X-Request-Sign: KrwDE9tAPJYBb4cUZU6ALJxGIZgwDXn5UkFPMip09n%2FkYKPhEIII%2Fki2rYY2lPtuKVgMNz%2BtuCU%2FjzRpohDbrOd8zYriiukpGAxBQDIVbatGI7WYOcc9YVQwdCR6ROuRQvr%2FD1AfdhHd6waAASu5Xugow9w1OW7Ti93LTd0tcyEWQYd2S7c3A73sHOJNYl8DC1PjasiBozZ%2FADgb7ONsqHo%2B8fKHsLygX9cuMkQYTGIRBQsvfgICnJhh%2BzXV8AQoecJBTrv6p%xxxx' \
-d '{
"after": "0",
"limit": 10,
"keyWord": "demo"
}'管控面介面
管控面介面提供與使用者相關的介面,基於使用者的 ak/sk 做許可權校正。主要用於同步應用開放平台空間下的相關資料。
目標APP(渠道)查詢介面
Path:
/openapi/v1/space/channel/queryMethod: POST
Content-Type: application/json
body:
{ "spaceCode": "1531602854311704010754", "currentPage": 1, "pageSize": 10 }response
{ "success":true, "model":{ "total":5, "list":[ { "spaceCode":"1531602854311704010754", "channelCode":"1611608397718512873472", "gmtCreate":1672306873348, "gmtModified":1677137552998, "name":"2test channel by gdm", "icon":"icon/channel/7aa28302a4b44859b397d2438e19d22d.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/7aa28302a4b44859b397d2438e19d22d.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T095150Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=f19482bc1e94100672c50846df67cf8668f329503292dbab6bcfb21bb95ee043", "description":"test channel of description", "status":"ONLINE" }, { "spaceCode":"1531602854311704010754", "channelCode":"1611638746437729390592", "gmtCreate":1679542571898, "gmtModified":1684482439359, "name":"jkkjkj", "icon":"icon/channel/db6330e973404d1183fbc9e38f207b7e.jpeg", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/db6330e973404d1183fbc9e38f207b7e.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T095150Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=4b5cf7c56d52a6a812ebd8169ab04b5744f39fea5a076e53e626db92255c4968", "description":"demo", "status":"ONLINE" } ], "pageSize":10, "current":1, "empty":false, "totalPages":1 } }
MiniApp 查詢介面
Path:
/openapi/v1/space/miniapp/queryMethod: POST
Content-Type: application/json
body:
{ "spaceCode": "1531602854311704010754", "currentPage": 1, "pageSize": 10 }response
{ "success":true, "model":{ "total":45, "list":[ { "spaceCode":"1531602854311704010754", "miniappCode":"1511686305220810936320", "gmtCreate":1690881469335, "gmtModified":1690881469335, "platform":"MiniApp", "framework":"WindVane", "name":"第三方111", "description":"", "slogan":"", "icon":"icon/channel/default_miniapp_icon.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/default_miniapp_icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T095456Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=5d121004dd1bfee918ce3504f67fa541104f3556b13d57ff8b27212e99043acb" }, { "spaceCode":"1531602854311704010754", "miniappCode":"1511686243166489821184", "gmtCreate":1690866674445, "gmtModified":1690874095536, "platform":"MiniApp", "framework":"WindVane", "name":"teest", "description":"", "slogan":"", "icon":"icon/channel/default_miniapp_icon.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/default_miniapp_icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T095456Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=5d121004dd1bfee918ce3504f67fa541104f3556b13d57ff8b27212e99043acb" } ], "pageSize":5, "current":1, "empty":false, "totalPages":9 } }
MiniApp 發布資訊查詢介面
Path:
/openapi/v1/space/miniapp/publishMethod: POST
Content-Type: application/json
body:
{ "spaceCode": "1531602854311704010754", "currentPage": 1, "pageSize": 10 }response:
{ "success":true, "model":{ "spaceCode":"1531602854311704010752", "miniappCode":"1511687342586899365888", "gmtCreate":1691128796684, "gmtModified":1691134056419, "platform":"MiniApp", "framework":"WindVane", "name":"WTF0804", "description":"", "slogan":"", "icon":"icon/channel/default_miniapp_icon.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/default_miniapp_icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T100031Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=59143f1fff5a849b08e4046590f972f4740f38fe5f899d38deffcfb92061c9db", "publishMiniappInfo":[ { "channelCode":"1611606158604452241408", "channelName":"SuperApp Channel test1_勿刪", "channelIcon":"icon/channel/393eaa3f7fef4205b34e5817310e6cf2.jpeg", "channelIconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/393eaa3f7fef4205b34e5817310e6cf2.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T100031Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=716456ad0355b10475da9afa6b0bc5c976a84d40c21fb1b4b3990cefa15bcab6", "gmtCreate":1691129052113, "gmtModified":1691134073490, "miniappCode":"1511687342586899365888", "onlineVersion":"0.0.5", "publishStatus":"ONLINE", "description":{ "inuseStatus":"ACTIVE", "name":"0.0.5", "description":"", "icon":"icon/channel/default_miniapp_icon.png", "iconPublicUrl":"http://47.103.xxx.xxx:7480/intercnn/icon/channel/default_miniapp_icon.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20230804T100031Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=IW2NNNAI0D8J2K8F7BPX%2F20230804%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=c419ed372b6827aa5ba540f95c4edad4bb8c168a37cb0005f3220922cb4dcd63" } } ] } }
管控介面簽名方式
管控介面簽名使用一方空間管理員帳號的accessKey和secretKey,對應的值請聯絡superapp開放平台營運人員擷取。簽名方式同SuperApp管理介面。
用戶端介面
收藏
Android
ServiceManager.getInstance().registerService(IMiniAppFavoriteService.class.getName(), new IMiniAppFavoriteService() { @Override public void addToFavorites(String appId, ServiceCallback callback) { //在這裡將小程式添加到收藏列表,收藏結果通過callback返回 } @Override public void removeFromFavorites(String appId, ServiceCallback callback) { //在這裡將小程式從收藏列表刪除,刪除結果通過callback返回 } @Override public boolean isFavorite(String appId) { //判斷小程式是否已經被收藏 return false; } });iOS
[[EMASServiceManager sharedInstance] registerServiceProtocol:@"EMASMiniAppFavoriteService" IMPClass:@"EMASMiniAppFavoriteServiceImpl" target:nil]; @implementation EMASMiniAppFavoriteServiceImpl - (void)addToFavorites:(NSString*)subAppCode completion:(nonnull EMASFavoriteCompletionBlock)completionBlock{ //在這裡將小程式添加到收藏列表,收藏結果通過block返回 } - (void)removeFromFavorites:(NSString*)subAppCode completion:(nonnull EMASFavoriteCompletionBlock)completionBlock{ //在這裡將小程式從收藏列表刪除,刪除結果通過block返回 } - (BOOL)isFavorite:(NSString*)subAppCode { //判斷小程式是否已經被收藏 return NO; } @end
最近使用
Android
IMiniAppService miniAppService = ServiceManager.getInstance().getService(IMiniAppService.class.getName()); if (miniAppService != null) { miniAppService.openMiniApp(mItemView.getContext(), ((MiniAppInfo) data).getAppId(), null, new OnOpenMiniAppListener() { @Override public void onOpenMiniApp() { } @Override public void onOpenSuccess(String appId) { //成功開啟小程式,在這裡可以將小程式記錄到最近使用列表中 } @Override public void onOpenFailed(String appId, int errorCode) { } }); }iOS
id<EMASMiniAppService> miniAppService = [[EMASServiceManager sharedInstance] serviceForProtocol:@"EMASMiniAppService"]; if (miniAppService) { [miniAppService openMiniApp:appId openConfiguration:nil completionBlock:^(int resultCode, NSDictionary * _Nonnull resultDict) { // resultCode 200為成功開啟 // 在這裡可以將小程式記錄到最近使用列表中 }]; }
擷取小程式中繼資料的容器介面
說明某些情境下,需要直接在用戶端擷取即時中繼資料時,可以使用該容器介面。
Android
IMiniAppService miniAppService = ServiceManager.getInstance().getService(IMiniAppService.class.getName()); if (miniAppService != null) { //appIds是要擷取中繼資料的小程式列表 miniAppService.getMiniAppInfos(this, appIds, new OnGetMiniAppsListener() { @Override public void onSuccess(List<MiniAppInfo> miniAppInfos) { //這裡返回小程式的中繼資料 } @Override public void onFailed(int errorCode) { } }); }iOS
id<EMASMiniAppService> miniAppService = [[EMASServiceManager sharedInstance] serviceForProtocol:@"EMASMiniAppService"]; if (miniAppService) { //appIds是要擷取中繼資料的小程式列表 [miniAppService getMiniAppInfo:appIds completionBlock:^(int resultCode, NSArray * _Nonnull miniApps) { // resultCode 200為成功 // 這裡返回小程式的中繼資料 }]; }
搜尋小程式
Android
IMiniAppService miniAppService = ServiceManager.getInstance().getService(IMiniAppService.class.getName()); if (miniAppService != null) { //keyword是搜尋關鍵詞 miniAppService.queryMiniApps(this, keyword, new OnQueryMiniAppsListener() { @Override public void onSuccess(List<MiniAppInfo> miniAppInfos, String anchor) { //返回搜尋結果,預設最多擷取10個,anchor用於擷取更多結果 } @Override public void onFailed(int errorCode) { } }); }iOS
id<EMASMiniAppService> miniAppService = [[EMASServiceManager sharedInstance] serviceForProtocol:@"EMASMiniAppService"]; if (miniAppService) { //keyword是搜尋關鍵詞,anchor預設為0 [miniAppService queryMiniApps:keyword anchor:anchor completionBlock:^(int resultCode, NSArray * _Nonnull miniApps, NSString *anchor) { // resultCode 200為成功 //返回搜尋結果,預設最多擷取10個,anchor用於擷取更多結果 }]; }
全量拉取小程式
Android
IMiniAppService miniAppService = ServiceManager.getInstance().getService(IMiniAppService.class.getName()); if (miniAppService != null) { // 設定keyword為空白 miniAppService.getMiniAppList(this, new OnGetMiniAppsListener() { @Override public void onSuccess(List<MiniAppInfo> miniAppInfos, String anchor) { // 小程式列表,預設最多擷取10個,anchor用於擷取更多小程式 } @Override public void onFailed(int errorCode) { } }); }iOS
id<EMASMiniAppService> miniAppService = [[EMASServiceManager sharedInstance] serviceForProtocol:@"EMASMiniAppService"]; if (miniAppService) { //anchor預設為0 [miniAppService getMiniAppList:anchor completionBlock:^(int resultCode, NSArray * _Nonnull miniApps, NSString *anchor) { // resultCode 200為成功 // 小程式列表,預設最多擷取10個,anchor用於擷取更多小程式 }]; }
術語解釋
SPI: service provider interface
