概述
在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
