## 关于小程序平台
小程序可以兼容以下小程序的应用框架:
* 微信小程序
* 百度小程序
* 阿里小程序
* 微信小游戏
* Web网页应用
用户可以将以上类型的小程序简单改造就可以植入平台
## 开发者如何开发小程序
下面是开发者开发小程序的时序图
![](https://web.potato.im/resources/images/app_progress.png)
步骤如下:
1. 商户通过"potato商户平台"按要求填写资料,申请AppId、以及API Key
2. 按照上面任意框架的规范编写小程序
3. 如果需要获取Potato的用户资料,调用登录授权接口获取权限
4. 如果需要支付功能,调用potato的支付接口
5. 把开发好的小程序上传到Potato的商户平台
6. 等待Potato官方对小程序进行审核
7. 审核通过则上架,未通过则通过邮件的方式通知商户未通过以及原因
## 本地方法调用示例
在编写小程序的过程中,可以通过Potato提供的API,方便的进行本地调用, 示例如下:
* 注意:
* `api.call`返回的都是`JSON对象`,不是`字符串`
##### 授权服务,请求用户登录token
接口说明,请参考`https://www.potato.im/api/loginSDK`, 其中调用此接口的参数获取方法如下:
1. access\_token: 在小程序中调用Potato提供的授权登录API,`requestOAuth`
2. client\_id: 在商户平台注册时返回的APP ID
3. client\_secret: 在商户平台注册时返回的API Key
* 前端调起potato授权示例:
* `注意`: 此处使用window.api和window.onloadw的含义请参考`小程序初始化`部分的说明
* 调用参数
* appid : 商户平台分配给小程序的APP ID
~~~javascript
if (window.api) {
this.callback();
} else {
window.onloadw = function() {
this.callback();
}
}
callback: function(){
window.api.call('requestOAuth', {appid: 'abcdefghijklmn'}, function(data) {
});
}
~~~
* 返回值
~~~javascript
{
"code": 1,
"data": {
"access_token": "abcd",
"code": 1,
"expires_in": "1565177880",
"message": "ok",
"scope": "userinfo",
"success": true,
"token_type": "bearer"
},
"message": "ok"
}
~~~
#### 支付
##### [接口详情请参考文档《ptpay 商户接口文档规范》](https://developer.potato.im/#/docs/payment#summary)
* 前端调用支付页面示例:
* 调用参数
* pcpay\_tid : 调用统一下单接口返回的订单号`orderId`
~~~javascript
window.api.call('payment', { "pcpay_tid":'2019012921727114226' }, function(data) {
})
~~~
* 返回值
* `注意`: 此返回值只是返回是否成功`调起了支付付款页面`,`而不是支付结果`
~~~javascript
{
"result":"true"// 此结果仅仅是返回是否成功调起了支付付款页面,切勿用于最终支付结果业务逻辑处理
}
~~~
#### 目前支持的其他接口(使用时请注意大小写)
launchMiniProgram 打开其他小程序
* 调用参数
* appId:要打开的小程序appId
* attach:开发者自定义的附加数据,后续可以用getAppUrl函数获取传递的attach参数.
~~~javascript
window.api.call('launchMiniProgram', {appId: "abcdefghijklmn", attach: "orderNo"}, function(data) {
})
~~~
* 返回值
~~~javascript
{
"result":true
}
~~~
shareToAppMessage 分享小程序
* 在聊天框和朋友圈分享小程序,由于`客户端原生的分享按钮无法自定义`shareInfo分享参数,可以先通过此函数传递自定义的分享信息,后续再使用getAppUrl函数获取传递的shareInfo参数
* `注意`:通过客户端原生的分享按钮分享小程序后可以通过监听`shareActionObserved`事件得知分享结果
~~~javascript
window.native.handler('shareActionObserved', function(data) {
console.log(JSON.stringify(data)) // true or false
});
~~~
* 调用参数
* shareInfo:要分享的数据,在getAppUrl函数中原样返回
~~~javascript
window.api.call('shareToAppMessage', { shareInfo: "abcdefg" }, function(data) {
})
~~~
* 返回值
~~~javascript
{
"result":true
}
~~~
getAppUrl 获取打开小程序的链接
* 可以获取launchMiniProgram函数里开发者自定义的附加参数信息(attach)
* 可以获取shareToAppMessage函数里开发者自定义的分享参数信息(shareInfo)
* 调用参数
* 无
~~~javascript
window.api.call('getAppUrl', {}, function(data) {
let url = data.result;
let obj = new Object();
if (url.indexOf("?") != -1) {
let str = url.substr(1);
let strs = str.split("&");
for(let i = 0; i < strs.length; i ++) {
obj[strs[i].split("=")[0]]=(strs[i].split("=")[1]);
}
}
console.log(JSON.stringify(obj))
})
~~~
* 返回值
~~~javascript
{
"result":"webapp://game?appid=abcdefghijklmn&shareInfo=abcdefg&attach=123456789"
}
~~~
getAppVersion 获取app版本
* 调用参数
* 无
~~~javascript
window.api.call('getAppVersion', {}, function(data) {
})
~~~
* 返回值
~~~javascript
{
"result":"version" // potato当前版本号
}
~~~
getAppLanguage 获取当前语音
* 调用参数
* 无
~~~javascript
window.api.call('getAppLanguage', {}, function(data) {
})
~~~
* 返回值
~~~javascript
{
"result":"language" // potato当前使用的语言
}
~~~
scanQR 扫描二维码
* 调用参数
* tips:扫描时,扫描框显示的提示标题
~~~javascript
window.api.call('scanQR', {'tips':'扫描分享码'}, function(data) {
})
~~~
* 返回值
~~~javascript
{
"result":"二维码扫描结果字符串"
}
~~~
close 关闭小程序接口
* 调用参数
* 无
~~~javascript
window.api.call('close', {}, function(data) {
})
~~~
* 返回值
* 无
## 小程序初始化
#### Web页面框架下的初始化
`api并不会`在页面加载时就加载,api是否成功加载,可以根据`window.api`是否为true来判断
我们为此添加了一个消息`window.onloadw`当这个消息被调用时,表示api已经就绪。
可以在代码中用`User-Agent`来判断是否是小程序框架`navigator.userAgent.match(/WebApp/)`.
~~~javascript
// 判断页面加载时,api是否成功加载
if (window.api) {
// 成功加载,立即执行callback
this.callback();
} else {
// 未成功加载,window.onloadw消息被调用后执行callback
window.onloadw = function() {
this.callback();
}
}
callback: function(){
console.log('test')
}
~~~
#### 获取小程序的初始化参数
~~~javascript
window.onloadw = function() {
console.log(wx.getInitParams()); // getInitParams() 返回值一般是介值对
};
~~~
## 小程序开发说明
### API
小程序通用API可以通过`window`上的`wx`对象访问,一般情况下也可以通过`mh`,`my`,`swan`对象访问.
这些api在所有版本的应用中都能访问到。
#### 本地数据
由于本地运行程序不会有域名,所以依靠域名的`js api`都会出现一些问题,比如`cookie`,`localStorage`等.
可以使用以下`api`代替
`wx.getStorageSync(key)`获得本地信息
* `key`(string)存储介
`wx.setStorageSync(key, value)`保存数据
* `key`(string)存储介
* `value`(string)储存值
`wx.clearStorageSync(key)`删除数据
#### 网络请求
在小程序使用`XMLHTTPRequest`可以满足基础请求限制,如果需要更加特别的请求,比如跨域等问题可以使用`request`, 或`wx.XMLHTTPRequest`;
`request(options)`网络请求(基本和微信小程序一致)
* `options`请求参数
* `data`请求参数数据,GET中会被无视
* `dataType`请求参数类型,GET中会被无视,如果`header`中有`content-type`,会替换掉默认值
1. `arraybuffer``data`会被转换为`Buffer`类型,默认`content-type`:`application/stream`
2. `text``data`会直接`toStirng`,默认`content-type`:`text/plain`
3. `json``data`会使用`JSON.stringify`,默认`content-type`:`application/json`
4. `urlencoded``data`会编码为url query,默认`content-type`:`application/x-www-form-urlencoded`
5. `formdata``data`会被编码为表单格式,默认`content-type`请不要更改。
* `header`请求headers,以介质对的方式传入header即可。
* `responseType`返回类型
1. `text`返回值会被转化为`String`
2. `json`返回值会被当作json转化为对象
3. `arraybuffer`返回值会作为`Buffer`类型返回
* `success(res)`请求成功回调
* `fail(res)`请求失败回调
* `complete(res)`请求完成回调
`wx.XMLHTTPRequest`参数与使用基本与`XMLHTTPRequest`一致。不过没有跨域限制,使用原生实现。
#### 保存图片到本地
~~~javascript
let req = wx.XMLHttpRequest();
req.open('GET', '/a.png');
req.responseType = 'arraybuffer';
req.onload =function() {
wx.fs.writeFileSync('tmp:///a.png', req.response);
wx.saveImageToPhotosAlbum({
filePath: 'tmp:///a.png',
success(res) {
console.log("Success " + JSON.stringify(res))
},
fail(err) {
console.log("Fail " + JSON.stringify(err))
}
})
}
req.send();
~~~
#### 打开页面或其他应用
`api.call('open', url)`即可打开url
在Web框架中,`window.open`会调用`api.call('open', url)`
#### 监听小程序隐藏或显示
* 小程序切换到后台运行,如果要处理相关业务时可以使用以下代码.
~~~javascript
window.addEventListener('loadw', function() {
native.handler('window.state', function(state) {
if (state.action === 'appear') {
console.log("隐藏小程序时暂停背景音乐")
} else if (state.action === 'disappear') {
console.log("显示小程序时恢复背景音乐")
}
});
});
~~~
#### 小程序获取渠道商信息
* 本地`根目录`新建`appletConfig.json`文件,里面可自定义配置渠道的参数.例如 :
~~~javascript
{
"channelId": 1,
"channelName ": "abc"
}
~~~
* 在小程序中使用`wx.getChanelInfoSync()`读取返回的json对象,获取参数.
* 提供给渠道商的时候,需要渠道商先给予相关渠道信息后覆盖此appletConfig.json文件里面的内容
#### 配置文件
小程序支持通过一些配置,让原生程序响应一些基础操作.
不同类型小程序各有不同分别是`app.json`,`game.json`和`web.json`
##### 配置如下
* window
* backgroundColor`//背景色 #FFFFFF`
* navigationBarTextStyle`//导航条文字颜色(小程序) white, black`
* navigationBarTitleText`//标题文本(小程序)`
* pageOrientation`//方向,横竖屏 landscape, portrait, auto`
* statusBarHidden`//隐藏状态条 true,false`
* keyboardAppear`//键盘出现时是否改变webView大小 'none', 'resize'`
* enableBackGesture`//原生的返回手势,会调用history.back()`
* fitSafeArea`//是否把webView移动去匹配safeArea`
~~~javascript
示例:web.json下追加以下代码
{
"window": {
"backgroundColor": "#FFFFFF",
"navigationBarTextStyle": "white",
"navigationBarTitleText": "最好的小程序",
"pageOrientation": "landscape",
"statusBarHidden": true,
"keyboardAppear": "resize",
"enableBackGesture": true,
"fitSafeArea": true
}
}
~~~
#### 请求更改配置
使用`wx.requireWindowFeature(feature)`可以在运行时请求动态更改配置
* 调用参数
* fullscreen`//是否全屏 true,false`
* orientation`//横竖屏 (portrait|landscape|'auto')`
* statusBarStyle`//白色还是暗色状态栏 (white|black)`
* enableGesture`//开启或关闭返回手势 true,false`
~~~javascript
wx.requireWindowFeature({
orientation: 'portrait'
})
~~~
* 返回值
* 无
#### 设备信息
`getSystemInfo`获得设备信息,`getSystemInfoSync`是同步版方法.
* 调用参数
* 无
~~~javascript
wx.getSystemInfo({
success:function(data){
console.log(JSON.stringify(data))
}
})
~~~
* 返回值
~~~javascript
{
brand: String,
model: String,
pixelRatio: Number,
screenWidth: Number,
screenHeight: Number,
windowWidth: Number,
windowHeight: Number,
statusBarHeight: Number,
language: String,
version: String,
system: String,
platform: String,
SDKVersion: String,
safeArea: Number,
/**
* @property {Object} safeArea2
* @property {Number} safeArea2.left
* @property {Number} safeArea2.right
* @property {Number} safeArea2.top
* @property {Number} safeArea2.bottom
* @property {Number} safeArea2.width
* @property {Number} safeArea2.height
*/
safeArea2: Object,
udid: String,
idfa: String, // iOS only
}
~~~
#### 小程序
这部分对应微信小程序,百度小程序,阿里小程序部分。
只需要小程序根目录存在`app.json`和`app.js`即判断为小程序
小程序框架可以解析微信,百度,阿里小程序的模版,然后渲染为html。
#### Web
一般情况把`index.html`更名为`web.html`即可
需要在Web型根目录存在`web.html`
## 上传小程序
详情请参考 "小程序商户平台"
* 注意:
* `打包一定要`在项目的`根目录下压缩为zip`,如果是以`Web应用`发布,一定要把`index.html`改为`web.html`
![packaging](https://developer.potato.im/statics/img/applet/package.gif)
## 小程序的审核与上架
小程序上传之后, 需要Potato官方通过审核 , 即可上线运行 。
## 快速方便的小程序分享方式
1. Potato内部通过@app机器人分享
在用户聊天框中简单的 @app 即可把应用方便的分享给好友,如下图所示:
![](https://www.potato.im/resources/images/look_for.jpg)