## 关于小程序平台 小程序可以兼容以下小程序的应用框架: * 微信小程序 * 百度小程序 * 阿里小程序 * 微信小游戏 * 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)