
HBuilderX android安卓手机 wifi无线调试
HBuilderX的安装包中有自带的adb 不需要自己重新下载
我的HBuilderX是最新的稳定版 目录是:
HBuilderX\plugins\launcher\tools\adbs
手机和电脑连接同一局域网(连同一个 WiFi)
运行cmd 切换到HBuilderX\plugins\launcher\tools\adbs
手机数据线连上电脑(打开允许usb调试),输入命令:adb tcpip <端口号>,<端口号> 可任意取,只要没被占用,如 6666
adb tcpip 6666 成功提示:restarting in TCP mode port :6666

查看手机的ip,输入命令 adb connect 192.168.2.102:666 此处192.168.2.102 替换为自己的ip
成功提示:connected to 192.168.2.102:6666
adb devices 可查看监听的设备
HBuilderX的安装包中有自带的adb 不需要自己重新下载
我的HBuilderX是最新的稳定版 目录是:
HBuilderX\plugins\launcher\tools\adbs
手机和电脑连接同一局域网(连同一个 WiFi)
运行cmd 切换到HBuilderX\plugins\launcher\tools\adbs
手机数据线连上电脑(打开允许usb调试),输入命令:adb tcpip <端口号>,<端口号> 可任意取,只要没被占用,如 6666
adb tcpip 6666 成功提示:restarting in TCP mode port :6666
查看手机的ip,输入命令 adb connect 192.168.2.102:666 此处192.168.2.102 替换为自己的ip
成功提示:connected to 192.168.2.102:6666
adb devices 可查看监听的设备
收起阅读 »
组件卸载之后取消未完成的请求
近期使用uni-app开发的项目中出现一个问题,在发起请求后如果用户直接点击的后退按钮,那么之前页面的请求还会继续加载,并且成功的时候依然会执行success的逻辑。
比如先从A页面跳转到B页面,然后在B页面查询数据,正常情况是查询成功后跳转到一个新的C页面,如果在请求成功之前用户不想去做后面的操作了,直接点击了浏览器的回退按钮,那么回退到A页面之后B页面的请求依然会继续执行,并且请求成功以后success的逻辑也会执行,会导致从A页面直接跳转的C页面。
最好的解决办法可能是①在离开一个页面后可以直接清空该页面组件的相关逻辑,并且停止页面内的请求?我找了一下没有看到这样的配置或者文档,所以不确定是否能够实现,并且如果有的页面逻辑是②:B页面同时发起两个请求task1,task2,在task1请求成功时会跳转页面,而task2的请求只负责传递数据,不做页面交互,那么在task1请求成功后页面跳转,B页面组件卸载直接停止task2请求的话可能也不合适。所以目前比较适合且可以实现的方式可能是在某些情况下手动停止请求。
关于uni.request停止请求的方法可以查看uni.request
直接使用uni.request的abort方法可以满足上方需求,但是写起来会比较麻烦,每一次请求都需要去保存对应的requestTask,在需要的时候再调用requestTask的abort方法。所以为了简化多请求的取消操作/写法,所以封装了一个方法。
我们的项目之前已经封装了uni.request方法,提供了自己的一些默认参数、请求头、返回数据处理以及错误提示等逻辑,这次在已有的基础上多加了取消请求的相关逻辑。这里我的思路是在发起请求时将当前requestTask作为一个对象的值存起来,对应的键可以是随机数或者guid格式的字符串,在请求成功或者失败后从对象中删除该键;当需要取消请求时把对象内的所有requestTask全部调用一次abort方法,以此取消请求。考虑到②的情况,所以暴露出去的request方法可以提供一个参数用于标识该请求是否可以被取消。而如果是希望实现①的情况的话,也可以监听路由变化,或者使用路由守卫,在页面变更时调用统一的取消请求方法。
import Vue from 'vue';
import { guid } from './utils.js';
let canCancelRequestObj = {};
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌过期)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const errortext = codeMessage[response.status] || response.statusText;
//校验不通过,则
const error = new Error(errortext);
error.name = response.status;
error.response = response;
throw error;
}
/**
- Requests a URL, returning a promise.
- @param {object} [options] The options we want to pass to "request"
-
@return {object} An object containing either "data" or "err"
*/
export default function request(options,canCancel=false) {
// const defaultOptions = {
// credentials: 'include',
// };
let requestId = guid();
console.log('canCancelRequestObj:',canCancelRequestObj);
if(!options.url){
console.log('无请求url')
return
}
const newOptions = {
// ...defaultOptions,
...options,
success(res) {
delete canCancelRequestObj[requestId];
// console.log('response:'+JSON.stringify(res));
if(res.statusCode == '401' || (res.statusCode != '200'&&!res.data)){
uni.hideLoading();
let strResult='';
//清空登陆信息,跳转到登陆页
console.log('登陆信息失效')
if(res.data){
strResult = res.data;
}else{
strResult = res.errMsg;
}
let jsondata = {
result: strResult
};
Vue.prototype && Vue.prototype.$bridge && Vue.prototype.$bridge.callhandler&&Vue.prototype.$bridge.callhandler('jsCallNative', {
action: 'goLogin',
data: JSON.stringify(jsondata)
}, (data) => {}); return } options.success&&options.success(res.data)
},
fail(error) {
if(error&&error.errMsg&&error.errMsg.includes('fail abort')){
console.log(error)
//主动取消的请求
return
}else{
options.fail&&options.fail(error)
}
}
};
let Authorization = window.sessionStorage.getItem('ACCESS_TOKEN');
newOptions.header = {
Authorization:Authorization,
from:'PSM_ANDROID',
timestamp:new Date().getTime(),
};
switch (uni.getSystemInfoSync().platform) {
case 'android':
newOptions.header.from = 'PSM_ANDROID';
break;
case 'ios':
newOptions.header.from = 'PSM_APPLE';
break;
default:
newOptions.header.from = 'PSM_APPLE';break;
}
if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'DELETE') {
newOptions.header = {
// Accept: 'application/json',
'content-type': 'application/json;',
...newOptions.header,
};
}
console.log(JSON.stringify(newOptions));
let requestTask = uni.request(newOptions);
if(canCancel){
canCancelRequestObj[requestId] = requestTask;
}
return requestTask;
}
export function cancelRequest (){
console.log(canCancelRequestObj);
if(!canCancelRequestObj||typeof canCancelRequestObj != 'object'){
return
}
Object.keys(canCancelRequestObj).forEach(item=>canCancelRequestObj[item].abort());
}
近期使用uni-app开发的项目中出现一个问题,在发起请求后如果用户直接点击的后退按钮,那么之前页面的请求还会继续加载,并且成功的时候依然会执行success的逻辑。
比如先从A页面跳转到B页面,然后在B页面查询数据,正常情况是查询成功后跳转到一个新的C页面,如果在请求成功之前用户不想去做后面的操作了,直接点击了浏览器的回退按钮,那么回退到A页面之后B页面的请求依然会继续执行,并且请求成功以后success的逻辑也会执行,会导致从A页面直接跳转的C页面。
最好的解决办法可能是①在离开一个页面后可以直接清空该页面组件的相关逻辑,并且停止页面内的请求?我找了一下没有看到这样的配置或者文档,所以不确定是否能够实现,并且如果有的页面逻辑是②:B页面同时发起两个请求task1,task2,在task1请求成功时会跳转页面,而task2的请求只负责传递数据,不做页面交互,那么在task1请求成功后页面跳转,B页面组件卸载直接停止task2请求的话可能也不合适。所以目前比较适合且可以实现的方式可能是在某些情况下手动停止请求。
关于uni.request停止请求的方法可以查看uni.request
直接使用uni.request的abort方法可以满足上方需求,但是写起来会比较麻烦,每一次请求都需要去保存对应的requestTask,在需要的时候再调用requestTask的abort方法。所以为了简化多请求的取消操作/写法,所以封装了一个方法。
我们的项目之前已经封装了uni.request方法,提供了自己的一些默认参数、请求头、返回数据处理以及错误提示等逻辑,这次在已有的基础上多加了取消请求的相关逻辑。这里我的思路是在发起请求时将当前requestTask作为一个对象的值存起来,对应的键可以是随机数或者guid格式的字符串,在请求成功或者失败后从对象中删除该键;当需要取消请求时把对象内的所有requestTask全部调用一次abort方法,以此取消请求。考虑到②的情况,所以暴露出去的request方法可以提供一个参数用于标识该请求是否可以被取消。而如果是希望实现①的情况的话,也可以监听路由变化,或者使用路由守卫,在页面变更时调用统一的取消请求方法。
import Vue from 'vue';
import { guid } from './utils.js';
let canCancelRequestObj = {};
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌过期)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
}
const errortext = codeMessage[response.status] || response.statusText;
//校验不通过,则
const error = new Error(errortext);
error.name = response.status;
error.response = response;
throw error;
}
/**
- Requests a URL, returning a promise.
- @param {object} [options] The options we want to pass to "request"
-
@return {object} An object containing either "data" or "err"
*/
export default function request(options,canCancel=false) {
// const defaultOptions = {
// credentials: 'include',
// };
let requestId = guid();
console.log('canCancelRequestObj:',canCancelRequestObj);
if(!options.url){
console.log('无请求url')
return
}
const newOptions = {
// ...defaultOptions,
...options,
success(res) {
delete canCancelRequestObj[requestId];
// console.log('response:'+JSON.stringify(res));
if(res.statusCode == '401' || (res.statusCode != '200'&&!res.data)){
uni.hideLoading();
let strResult='';
//清空登陆信息,跳转到登陆页
console.log('登陆信息失效')
if(res.data){
strResult = res.data;
}else{
strResult = res.errMsg;
}
let jsondata = {
result: strResult
};
Vue.prototype && Vue.prototype.$bridge && Vue.prototype.$bridge.callhandler&&Vue.prototype.$bridge.callhandler('jsCallNative', {
action: 'goLogin',
data: JSON.stringify(jsondata)
}, (data) => {}); return } options.success&&options.success(res.data)
},
fail(error) {
if(error&&error.errMsg&&error.errMsg.includes('fail abort')){
console.log(error)
//主动取消的请求
return
}else{
options.fail&&options.fail(error)
}
}
};
let Authorization = window.sessionStorage.getItem('ACCESS_TOKEN');
newOptions.header = {
Authorization:Authorization,
from:'PSM_ANDROID',
timestamp:new Date().getTime(),
};
switch (uni.getSystemInfoSync().platform) {
case 'android':
newOptions.header.from = 'PSM_ANDROID';
break;
case 'ios':
newOptions.header.from = 'PSM_APPLE';
break;
default:
newOptions.header.from = 'PSM_APPLE';break;
}
if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'DELETE') {
newOptions.header = {
// Accept: 'application/json',
'content-type': 'application/json;',
...newOptions.header,
};
}
console.log(JSON.stringify(newOptions));
let requestTask = uni.request(newOptions);
if(canCancel){
canCancelRequestObj[requestId] = requestTask;
}
return requestTask;
}
export function cancelRequest (){
console.log(canCancelRequestObj);
if(!canCancelRequestObj||typeof canCancelRequestObj != 'object'){
return
}
Object.keys(canCancelRequestObj).forEach(item=>canCancelRequestObj[item].abort());
}

基于uniCloud/静态托管实现苹果IEP证书类型的ipa下载安装服务
uniCloud 是 DCloud 联合阿里云、腾讯云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。
uniCloud
的 web控制台地址:https://unicloud.dcloud.net.cn
Apple Developer Enterprise Program
可让大型组织开发内部专属的 app 并向其员工部署。此计划仅适用于需要使用安全的内部系统或经由移动设备管理解决方案,向员工私密地直接分发的特例情况。详情:https://developer.apple.com/cn/programs/enterprise/
原 IEP
(iOS Developer Enterprise Program),已统一为 Apple Developer Enterprise Program
步骤如下
第1步
开通uniCloud,详情 https://unicloud.dcloud.net.cn/
第2步
在 uniCloud web控制台左侧栏 "前端网页托管" 上传5个文件,目录结构如下
根目录 >
| app_name_v3.0.0.ipa
| manifest.plist
| index.html
| icon_58.png
| icon_512.png
文件目录介绍
app_name_v3.0.0.ipa 是使用`IEP`证书的应用安装包
manifest.plist 是应用的描述文件
index.html 是用户安装应用页面
icon_58.png 是应用显示的图标,分辨率 58x58,名字可自定义
icon_512.png 是应用的最大图标,分辨率 512x512,名字可自定义
manifest.plist
配置
- 新建文件 manifest.plist 文件并粘贴下面
新闻模板
的 manifest.plist 配置,.plist 是扩展名 - 替换 manifest.plist 文件内容为你的应用信息
- 在 manifest.plist 搜索应用名称
新闻模板
- 在 manifest.plist 搜索应用下载地址
https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa
- 在 manifest.plist 搜索icon_58.png图标
https://static-xxxx.bspapp.com/download/icon_58.png
- 在 manifest.plist 搜索icon_512.png图标
https://static-xxxx.bspapp.com/download/icon_512.png
- 在 manifest.plist 搜索应用名称
注意:
https://static-xxxx.bspapp.com/
是前端网页托管的默认域名,腾讯和阿里的不同,可绑定自己的域名manifest.plist
可配置不同设备的.ipa,例如 iPad, iPhone,示例中共用了一个.ipa- 安装包是有有效期的,过期后需要更新证书重新打包
新闻模板
的 manifest.plist
配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/icon_58.png</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/icon_512.png</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>io.dcloud.new.template</string>
<key>bundle-version</key>
<string>2.4.3</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>新闻模板</string>
</dict>
<key>thinned-assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone6,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone6,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone7,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone8,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone8,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPod7,1</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array/>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone8,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,3</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPhone11,6</string>
<string>iPhone11,2</string>
<string>iPhone11,4</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPad5,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,9</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,12</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,11</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,2</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPad8,1</string>
<string>iPad8,8</string>
<string>iPad8,7</string>
<string>iPad8,6</string>
<string>iPad8,5</string>
<string>iPad8,4</string>
<string>iPad8,3</string>
<string>iPad8,2</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad3,6</string>
<string>iPad3,4</string>
<string>iPad3,2</string>
<string>iPad3,5</string>
<string>iPad3,3</string>
<string>iPad3,1</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone11,8</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPhone11,8</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone10,2</string>
<string>iPhone7,1</string>
<string>iPhone10,6</string>
<string>iPhone10,5</string>
<string>iPhone8,2</string>
<string>iPhone9,4</string>
<string>iPhone10,3</string>
<string>iPhone9,2</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone5,2</string>
<string>iPod5,1</string>
<string>iPhone5,3</string>
<string>iPhone4,1</string>
<string>iPhone5,1</string>
<string>iPhone5,4</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad7,4</string>
<string>iPad4,5</string>
<string>iPad7,5</string>
<string>iPad4,6</string>
<string>iPad6,3</string>
<string>iPad5,1</string>
<string>iPad6,11</string>
<string>iPad7,6</string>
<string>iPad5,2</string>
<string>iPad6,4</string>
<string>iPad4,7</string>
<string>iPad5,3</string>
<string>iPad4,1</string>
<string>iPad4,8</string>
<string>iPad6,12</string>
<string>iPad7,1</string>
<string>iPad5,4</string>
<string>iPad4,9</string>
<string>iPad4,2</string>
<string>iPad7,2</string>
<string>iPad4,3</string>
<string>iPad6,7</string>
<string>iPad7,3</string>
<string>iPad4,4</string>
<string>iPad6,8</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone10,1</string>
<string>iPhone8,1</string>
<string>iPhone9,3</string>
<string>iPhone6,2</string>
<string>iPhone9,1</string>
<string>iPhone7,2</string>
<string>iPod7,1</string>
<string>iPhone10,4</string>
<string>iPhone8,4</string>
<string>iPhone6,1</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad2,3</string>
<string>iPad2,2</string>
<string>iPad2,1</string>
<string>iPad2,7</string>
<string>iPad2,6</string>
<string>iPad2,5</string>
<string>iPad2,4</string>
</array>
</dict>
</array>
</dict>
</array>
</dict>
</plist>
第3步
index.html 内容
需要替换 a
标签的 href
属性,用户点击 a 标签后将弹出下载确认框
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello news</title>
<meta name="author" content="dcloud">
<meta name="description" content="hello news">
<meta name="keywords" content="hello news,dcloud">
<meta name="viewport" content="width=device-width,user-scalable=no">
</head>
<body>
<!-- https://static-xxx.bspapp.com/download/manifest.plist 替换为你的前端网页托管中的 manifest.plist 文件目录 -->
<a href="itms-services://?action=download-manifest&url=https://static-xxx.bspapp.com/download/manifest.plist">下载 iOS hello news</a>
</body>
</html>
第4步
使用手机浏览器访问你的前端网页托管地址,示例: https://static-xxx.bspapp.com/
uniCloud 是 DCloud 联合阿里云、腾讯云,为开发者提供的基于 serverless 模式和 js 编程的云开发平台。
uniCloud
的 web控制台地址:https://unicloud.dcloud.net.cn
Apple Developer Enterprise Program
可让大型组织开发内部专属的 app 并向其员工部署。此计划仅适用于需要使用安全的内部系统或经由移动设备管理解决方案,向员工私密地直接分发的特例情况。详情:https://developer.apple.com/cn/programs/enterprise/
原 IEP
(iOS Developer Enterprise Program),已统一为 Apple Developer Enterprise Program
步骤如下
第1步
开通uniCloud,详情 https://unicloud.dcloud.net.cn/
第2步
在 uniCloud web控制台左侧栏 "前端网页托管" 上传5个文件,目录结构如下
根目录 >
| app_name_v3.0.0.ipa
| manifest.plist
| index.html
| icon_58.png
| icon_512.png
文件目录介绍
app_name_v3.0.0.ipa 是使用`IEP`证书的应用安装包
manifest.plist 是应用的描述文件
index.html 是用户安装应用页面
icon_58.png 是应用显示的图标,分辨率 58x58,名字可自定义
icon_512.png 是应用的最大图标,分辨率 512x512,名字可自定义
manifest.plist
配置
- 新建文件 manifest.plist 文件并粘贴下面
新闻模板
的 manifest.plist 配置,.plist 是扩展名 - 替换 manifest.plist 文件内容为你的应用信息
- 在 manifest.plist 搜索应用名称
新闻模板
- 在 manifest.plist 搜索应用下载地址
https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa
- 在 manifest.plist 搜索icon_58.png图标
https://static-xxxx.bspapp.com/download/icon_58.png
- 在 manifest.plist 搜索icon_512.png图标
https://static-xxxx.bspapp.com/download/icon_512.png
- 在 manifest.plist 搜索应用名称
注意:
https://static-xxxx.bspapp.com/
是前端网页托管的默认域名,腾讯和阿里的不同,可绑定自己的域名manifest.plist
可配置不同设备的.ipa,例如 iPad, iPhone,示例中共用了一个.ipa- 安装包是有有效期的,过期后需要更新证书重新打包
新闻模板
的 manifest.plist
配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>items</key>
<array>
<dict>
<key>assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
</dict>
<dict>
<key>kind</key>
<string>display-image</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/icon_58.png</string>
</dict>
<dict>
<key>kind</key>
<string>full-size-image</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/icon_512.png</string>
</dict>
</array>
<key>metadata</key>
<dict>
<key>bundle-identifier</key>
<string>io.dcloud.new.template</string>
<key>bundle-version</key>
<string>2.4.3</string>
<key>kind</key>
<string>software</string>
<key>title</key>
<string>新闻模板</string>
</dict>
<key>thinned-assets</key>
<array>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone6,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone6,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone7,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone8,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone8,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPod7,1</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array/>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone8,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone11,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone9,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPhone10,3</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPhone11,6</string>
<string>iPhone11,2</string>
<string>iPhone11,4</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPad5,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,9</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,6</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,3</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,7</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,12</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad5,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,11</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,5</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,1</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad7,4</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad8,2</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad6,8</string>
<key>os-version</key>
<string>12</string>
</dict>
<dict>
<key>device</key>
<string>iPad4,2</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPad8,1</string>
<string>iPad8,8</string>
<string>iPad8,7</string>
<string>iPad8,6</string>
<string>iPad8,5</string>
<string>iPad8,4</string>
<string>iPad8,3</string>
<string>iPad8,2</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad3,6</string>
<string>iPad3,4</string>
<string>iPad3,2</string>
<string>iPad3,5</string>
<string>iPad3,3</string>
<string>iPad3,1</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array>
<dict>
<key>device</key>
<string>iPhone11,8</string>
<key>os-version</key>
<string>12</string>
</dict>
</array>
<key>variantIds</key>
<array>
<string>iPhone11,8</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone10,2</string>
<string>iPhone7,1</string>
<string>iPhone10,6</string>
<string>iPhone10,5</string>
<string>iPhone8,2</string>
<string>iPhone9,4</string>
<string>iPhone10,3</string>
<string>iPhone9,2</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone5,2</string>
<string>iPod5,1</string>
<string>iPhone5,3</string>
<string>iPhone4,1</string>
<string>iPhone5,1</string>
<string>iPhone5,4</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad7,4</string>
<string>iPad4,5</string>
<string>iPad7,5</string>
<string>iPad4,6</string>
<string>iPad6,3</string>
<string>iPad5,1</string>
<string>iPad6,11</string>
<string>iPad7,6</string>
<string>iPad5,2</string>
<string>iPad6,4</string>
<string>iPad4,7</string>
<string>iPad5,3</string>
<string>iPad4,1</string>
<string>iPad4,8</string>
<string>iPad6,12</string>
<string>iPad7,1</string>
<string>iPad5,4</string>
<string>iPad4,9</string>
<string>iPad4,2</string>
<string>iPad7,2</string>
<string>iPad4,3</string>
<string>iPad6,7</string>
<string>iPad7,3</string>
<string>iPad4,4</string>
<string>iPad6,8</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPhone10,1</string>
<string>iPhone8,1</string>
<string>iPhone9,3</string>
<string>iPhone6,2</string>
<string>iPhone9,1</string>
<string>iPhone7,2</string>
<string>iPod7,1</string>
<string>iPhone10,4</string>
<string>iPhone8,4</string>
<string>iPhone6,1</string>
</array>
</dict>
<dict>
<key>kind</key>
<string>software-package</string>
<key>url</key>
<string>https://static-xxxx.bspapp.com/download/hello_news_v3.0.0.ipa</string>
<key>variantDescriptors</key>
<array/>
<key>variantIds</key>
<array>
<string>iPad2,3</string>
<string>iPad2,2</string>
<string>iPad2,1</string>
<string>iPad2,7</string>
<string>iPad2,6</string>
<string>iPad2,5</string>
<string>iPad2,4</string>
</array>
</dict>
</array>
</dict>
</array>
</dict>
</plist>
第3步
index.html 内容
需要替换 a
标签的 href
属性,用户点击 a 标签后将弹出下载确认框
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>hello news</title>
<meta name="author" content="dcloud">
<meta name="description" content="hello news">
<meta name="keywords" content="hello news,dcloud">
<meta name="viewport" content="width=device-width,user-scalable=no">
</head>
<body>
<!-- https://static-xxx.bspapp.com/download/manifest.plist 替换为你的前端网页托管中的 manifest.plist 文件目录 -->
<a href="itms-services://?action=download-manifest&url=https://static-xxx.bspapp.com/download/manifest.plist">下载 iOS hello news</a>
</body>
</html>
第4步
使用手机浏览器访问你的前端网页托管地址,示例: https://static-xxx.bspapp.com/

万岳在线教育系统UNI-APP开源版
如果您是初学者,uni-app如何用于开发一定是一个颇为头疼且无从下手的问题。如果能有一个开源项目作为参考,一定能让您的学习事半功倍。我们万岳科技的在线教育系统UNI-APP开源版就是通过uni-app开发的开源系统的前端部分,uni-app的各种核心技术都有应用。有它一定能让您的学习轻松不少。
- <a target="_blank" href="http://doc.sdwanyue.com/wanyue_open_uniapp/2100689">部署文档</a>
系统演示
Web版地址
- 首页地址: <a target="_blank" href="https://demo.sdwanyue.com">https://demo.sdwanyue.com</a>
- 学生端地址: <a target="_blank" href="https://demo.sdwanyue.com">https://demo.sdwanyue.com</a> 账号:13800000000 密码:123456
- 教师端地址: <a target="_blank" href="https://demo.sdwanyue.com/teacher">https://demo.sdwanyue.com/teacher</a> 账号:13866666666 密码:123456
- 后台地址: <a target="_blank" href="https://demo.sdwanyue.com/admin">https://demo.sdwanyue.com/admin</a> 账号: demo 密码: 123456
- 仓库地址: <a target="_blank" href="https://gitee.com/WanYueKeJi/wanyue_education_web">点击此处</a>
项目介绍
万岳在线教育经过对教育市场的长期调研,综合当下各大线上教培机构对于教育平台的功能需求,着重于用户体验,自主研发了一套集知识付费、直播授课、网校建设等功能为一体的万岳在线教育系统,满足用户对于公开课、大班课、小班课、职业培训等多种线上教学活动的场景需求。
- 所有使用到的框架或者组件都是基于开源项目,代码保证100%开源。
- 系统功能通用,无论是个人还是企业都可以利用该系统快速搭建一个属于自己的在线教育平台。
系统前端采用uni-app+socket.io+WebRtc核心技术, 接口采用PhalApi框架配合TP5.1框架ThinkCMF,系统功能如下:
技术亮点
UNI-APP端:
1.一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序
2.依托Dcloud公司强大的生态圈, 开发者无论是拿来直接用还是自己修改后使用都
十分的方便, 网上资料/文档齐全,无需担心bug解决不了.
3.支持视频直播、聊天等即时通讯功能, 开源项目有很多,可是带聊天室和直播的寥寥可数.
4.本项目已内置好socket.io组件和声网WebRtc插件, 开发者可直接拿来调试学习.
无需再从基本的websocket写起.
5.项目占用空间小,全部加起来不到2MB,占用开发者磁盘空间极少.
6.代码中做了多端适配, 小程序端、H5端、安卓、IOS端样式都做到了样式兼容.
7.vue/nvue混合开发, 保证了样式美观的同时, 规避了nvue样式的兼容问题.
8.配置方便, 无需安装, 下载之后使用Hbuilder编辑器即可运行查看.
后端:
1.后台应用ThinkCMF快速生成现代化表单.
2.PHPExcel数据导出,导出表格更加美观,可视.
3.支持微信/支付宝支付,支付接入更加快捷,简单.
4.后台多任务窗口化操作界面.
5.内置强大灵活的权限管理.
6.内置组合数据,系统配置,管理碎片化数据.
7.客户端完善的交互效果和动画.
8.高频数据缓存.
9.内置PhalApi接口框架,前后端分离更方便.
10.WebSocket长连接减少CPU及内存使用及网络堵塞,减少请求响应时长.
11.支持队列降低流量高峰,解除耦合,高可用.
12.无需安装, clone下来即可直接使用, 完全100%真开源.
注:关于PC端源码请看本公司另一个开源项目, 万岳在线教育系统Web版,
此两个项目是互通的
功能展示
主要功能介绍
讲师PC端
-
登录页面,可通过手机号码及验证码或密码进行登录,支持qq、微信帐号登录
-
首页功能,展示老师头像、名称,我的直播课数量,我的课程数量,常用功能以及常见问题
-
直播课堂,
1.语音大班课
语音大班课内,讲师可进入课程根据视频和语音对学生进行讲解2.视频大班课
视频大班课讲师可以进行开启摄像头、上传ppt图片课件、屏幕共享操作 -
账号,展示头像、昵称等账号信息,可编辑头像、昵称
学生UNI-APP端
-
首页,
1.搜索 可根据课程、老师名称关键字查询搜索
2.轮播图 后台添加的轮播图展示
3.直播课堂 直播课展示列表, 直播分为三种类型(语音+视频、语音+音频、语音+ppt+摄像头直播)
4.精选内容 内容展示列表,包含封面、标题、内容类型(视频、音频、图文)
-
精选内容,
1.详情页 由上往下依次展示封面图、课程标题,学习人数、主讲老师与辅导老师、课程类型(分为密码、免费、付费三种类型)等
2.查看详情 上部为视频、音频播放区域,视频、音频支持进度条滑动查看,视频可全屏观看,播放区域下方为内容标题、简介、发布时间等信息和详细内容展示(支持图文)
-
直播课堂,
1.语音大班课
2.视频大班课
-
后台主要功能介绍
-
设置
1.网站信息 网站的相关信息及SEO设置
2.私密设置 配置系统的重要参数(包登录配置、直播配置、云存储设置)
3.幻灯片管理 首页轮播banner图管理配置
4.上传设置 上传信息相关配置
5.文件存储 文件存储信息相关配置
-
用户管理
1.管理组 编辑后台管理员身份及权限等相关配置
2.用户列表 平台所有注册用户信息列表,可进行编辑、设置讲师资格、禁用、删除等操作
3.教师列表 后台将普通用户设置为讲师的用户显示在此处
-
插件中心
1.插件列表 查看编辑应用插件信息
-
内容管理
1.文章管理 网站相关文章配置
2.分类管理 文章分类管理
3.页面管理 联系我们、关于我们等单页内容配置
-
订单管理
1.展示用户购买课程后展示的会员名称、购买价格、订单号、需要线下邮寄教材的收货信息与支付方式与状态
-
知识管理
1.学级分类 登录页的学习阶段分类,可在后台自行添加
2.付费内容列表 展示添加的所有需要付费/免费的文章内容,可查看平台所有内容信息。 -
大班课列表
1.语音大班课
2.视频大班课
页面展示
直播课页面
功能对比
开源版使用须知
-
允许用于个人学习、教学案例
-
开源版不适合商用,商用请购买商业版
-
禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负
商业合作
- 如果你想使用功能更完善的教育系统,请联系QQ客服: 2415408120获取专业版
- 如果您想基于教育系统进行定制开发,我们提供有偿定制服务支持!
- 其他合作模式不限,欢迎来撩!
- 官网地址:http://www.sdwanyue.com
如果您是初学者,uni-app如何用于开发一定是一个颇为头疼且无从下手的问题。如果能有一个开源项目作为参考,一定能让您的学习事半功倍。我们万岳科技的在线教育系统UNI-APP开源版就是通过uni-app开发的开源系统的前端部分,uni-app的各种核心技术都有应用。有它一定能让您的学习轻松不少。
- <a target="_blank" href="http://doc.sdwanyue.com/wanyue_open_uniapp/2100689">部署文档</a>
系统演示
Web版地址
- 首页地址: <a target="_blank" href="https://demo.sdwanyue.com">https://demo.sdwanyue.com</a>
- 学生端地址: <a target="_blank" href="https://demo.sdwanyue.com">https://demo.sdwanyue.com</a> 账号:13800000000 密码:123456
- 教师端地址: <a target="_blank" href="https://demo.sdwanyue.com/teacher">https://demo.sdwanyue.com/teacher</a> 账号:13866666666 密码:123456
- 后台地址: <a target="_blank" href="https://demo.sdwanyue.com/admin">https://demo.sdwanyue.com/admin</a> 账号: demo 密码: 123456
- 仓库地址: <a target="_blank" href="https://gitee.com/WanYueKeJi/wanyue_education_web">点击此处</a>
项目介绍
万岳在线教育经过对教育市场的长期调研,综合当下各大线上教培机构对于教育平台的功能需求,着重于用户体验,自主研发了一套集知识付费、直播授课、网校建设等功能为一体的万岳在线教育系统,满足用户对于公开课、大班课、小班课、职业培训等多种线上教学活动的场景需求。
- 所有使用到的框架或者组件都是基于开源项目,代码保证100%开源。
- 系统功能通用,无论是个人还是企业都可以利用该系统快速搭建一个属于自己的在线教育平台。
系统前端采用uni-app+socket.io+WebRtc核心技术, 接口采用PhalApi框架配合TP5.1框架ThinkCMF,系统功能如下:
技术亮点
UNI-APP端:
1.一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序
2.依托Dcloud公司强大的生态圈, 开发者无论是拿来直接用还是自己修改后使用都
十分的方便, 网上资料/文档齐全,无需担心bug解决不了.
3.支持视频直播、聊天等即时通讯功能, 开源项目有很多,可是带聊天室和直播的寥寥可数.
4.本项目已内置好socket.io组件和声网WebRtc插件, 开发者可直接拿来调试学习.
无需再从基本的websocket写起.
5.项目占用空间小,全部加起来不到2MB,占用开发者磁盘空间极少.
6.代码中做了多端适配, 小程序端、H5端、安卓、IOS端样式都做到了样式兼容.
7.vue/nvue混合开发, 保证了样式美观的同时, 规避了nvue样式的兼容问题.
8.配置方便, 无需安装, 下载之后使用Hbuilder编辑器即可运行查看.
后端:
1.后台应用ThinkCMF快速生成现代化表单.
2.PHPExcel数据导出,导出表格更加美观,可视.
3.支持微信/支付宝支付,支付接入更加快捷,简单.
4.后台多任务窗口化操作界面.
5.内置强大灵活的权限管理.
6.内置组合数据,系统配置,管理碎片化数据.
7.客户端完善的交互效果和动画.
8.高频数据缓存.
9.内置PhalApi接口框架,前后端分离更方便.
10.WebSocket长连接减少CPU及内存使用及网络堵塞,减少请求响应时长.
11.支持队列降低流量高峰,解除耦合,高可用.
12.无需安装, clone下来即可直接使用, 完全100%真开源.
注:关于PC端源码请看本公司另一个开源项目, 万岳在线教育系统Web版,
此两个项目是互通的
功能展示
主要功能介绍
讲师PC端
-
登录页面,可通过手机号码及验证码或密码进行登录,支持qq、微信帐号登录
-
首页功能,展示老师头像、名称,我的直播课数量,我的课程数量,常用功能以及常见问题
-
直播课堂,
1.语音大班课
语音大班课内,讲师可进入课程根据视频和语音对学生进行讲解2.视频大班课
视频大班课讲师可以进行开启摄像头、上传ppt图片课件、屏幕共享操作 -
账号,展示头像、昵称等账号信息,可编辑头像、昵称
学生UNI-APP端
-
首页,
1.搜索 可根据课程、老师名称关键字查询搜索
2.轮播图 后台添加的轮播图展示
3.直播课堂 直播课展示列表, 直播分为三种类型(语音+视频、语音+音频、语音+ppt+摄像头直播)
4.精选内容 内容展示列表,包含封面、标题、内容类型(视频、音频、图文)
-
精选内容,
1.详情页 由上往下依次展示封面图、课程标题,学习人数、主讲老师与辅导老师、课程类型(分为密码、免费、付费三种类型)等
2.查看详情 上部为视频、音频播放区域,视频、音频支持进度条滑动查看,视频可全屏观看,播放区域下方为内容标题、简介、发布时间等信息和详细内容展示(支持图文)
-
直播课堂,
1.语音大班课
2.视频大班课
-
后台主要功能介绍
-
设置
1.网站信息 网站的相关信息及SEO设置
2.私密设置 配置系统的重要参数(包登录配置、直播配置、云存储设置)
3.幻灯片管理 首页轮播banner图管理配置
4.上传设置 上传信息相关配置
5.文件存储 文件存储信息相关配置
-
用户管理
1.管理组 编辑后台管理员身份及权限等相关配置
2.用户列表 平台所有注册用户信息列表,可进行编辑、设置讲师资格、禁用、删除等操作
3.教师列表 后台将普通用户设置为讲师的用户显示在此处
-
插件中心
1.插件列表 查看编辑应用插件信息
-
内容管理
1.文章管理 网站相关文章配置
2.分类管理 文章分类管理
3.页面管理 联系我们、关于我们等单页内容配置
-
订单管理
1.展示用户购买课程后展示的会员名称、购买价格、订单号、需要线下邮寄教材的收货信息与支付方式与状态
-
知识管理
1.学级分类 登录页的学习阶段分类,可在后台自行添加
2.付费内容列表 展示添加的所有需要付费/免费的文章内容,可查看平台所有内容信息。 -
大班课列表
1.语音大班课
2.视频大班课
页面展示
直播课页面
功能对比
开源版使用须知
-
允许用于个人学习、教学案例
-
开源版不适合商用,商用请购买商业版
-
禁止将本项目的代码和资源进行任何形式的出售,产生的一切任何后果责任由侵权者自负
商业合作
- 如果你想使用功能更完善的教育系统,请联系QQ客服: 2415408120获取专业版
- 如果您想基于教育系统进行定制开发,我们提供有偿定制服务支持!
- 其他合作模式不限,欢迎来撩!
- 官网地址:http://www.sdwanyue.com

可获取MD5签名的JDK版本 分享
目前部分 应用服务(比如一键登录)需要提供 android应用的MD5证书签名
但是最新版本的JDK 已经不支持MD5了,仅支持sha1,sha256两种签名。
分享一下可以获取MD5签名的旧版本JDK
链接:https://pan.baidu.com/s/1U4SWoYY6Gn4B4PjSJwy9Gg
提取码:tm85
感谢 热心开发者 @759416651@qq.com 的分享
目前部分 应用服务(比如一键登录)需要提供 android应用的MD5证书签名
但是最新版本的JDK 已经不支持MD5了,仅支持sha1,sha256两种签名。
分享一下可以获取MD5签名的旧版本JDK
链接:https://pan.baidu.com/s/1U4SWoYY6Gn4B4PjSJwy9Gg
提取码:tm85
感谢 热心开发者 @759416651@qq.com 的分享
收起阅读 »
关于解决live-pusher只推麦克风
在uniapp中有这么一个问题是 enable-camera 在并不管用。
会出现会出现如下错误
别着急,你可以参考以下代码试一下会发现查看视频流的时候没有画面只有声音。
export default {
data() {
return {
url: 'rtmp://92926.livepush.myqcloud.com/live/123',
enableCamera: false,
context: null
};
},
onReady() {
this.context = uni.createLivePusherContext('livePusher', this);
},
methods: {
EnableCamera() {
this.enableCamera = false;
},
startLive() {
this.context.start({
success: a => {
console.log('livePusher.start:' JSON.stringify(a));
}
});
},
stopLive() {
this.context.stop({
success: a => {
console.log(JSON.stringify(a));
}
});
}
}
};
但是到了这一步你以为就完成了吗?不!你会发现还是跟之前一样申请了摄像头跟麦克风。而我的需求是只需要推麦克风;
别着急这也能实现。看图
如图所示只需加上enable-camera="false"就能解决了!!!
如果你有其它问题可联系QQ1437448122一起交流
在uniapp中有这么一个问题是 enable-camera 在并不管用。
会出现会出现如下错误
别着急,你可以参考以下代码试一下会发现查看视频流的时候没有画面只有声音。
export default {
data() {
return {
url: 'rtmp://92926.livepush.myqcloud.com/live/123',
enableCamera: false,
context: null
};
},
onReady() {
this.context = uni.createLivePusherContext('livePusher', this);
},
methods: {
EnableCamera() {
this.enableCamera = false;
},
startLive() {
this.context.start({
success: a => {
console.log('livePusher.start:' JSON.stringify(a));
}
});
},
stopLive() {
this.context.stop({
success: a => {
console.log(JSON.stringify(a));
}
});
}
}
};
但是到了这一步你以为就完成了吗?不!你会发现还是跟之前一样申请了摄像头跟麦克风。而我的需求是只需要推麦克风;
别着急这也能实现。看图
如图所示只需加上enable-camera="false"就能解决了!!!
如果你有其它问题可联系QQ1437448122一起交流
收起阅读 »
mui ajax 封装成Promise <仅供参考> 可以优雅的使用 async/await
import mui from '@/assets/mui/js/mui'
const { ajax } = mui
function promiseAjax (url, type, params, options = {}) {
return new Promise((res, rej) => {
try {
ajax(url, {
data: params,
dataType: options.dataType || 'json',//服务器返回json格式数据
type: type,//HTTP请求类型
timeout: options.timeout || 10000,//超时时间设置为10秒;
headers: options.headers || { 'Content-Type': 'application/json' },
success: function (data) {
res(data)
},
error: function (xhr, type, errorThrown) {
rej(errorThrown)
},
})
} catch (e) {
rej(e)
}
})
}
export default {
get (url, params, options) {
return promiseAjax(url, 'get', params, options)
},
post (url, params, options) {
return promiseAjax(url, 'post', params, options)
},
}
import mui from '@/assets/mui/js/mui'
const { ajax } = mui
function promiseAjax (url, type, params, options = {}) {
return new Promise((res, rej) => {
try {
ajax(url, {
data: params,
dataType: options.dataType || 'json',//服务器返回json格式数据
type: type,//HTTP请求类型
timeout: options.timeout || 10000,//超时时间设置为10秒;
headers: options.headers || { 'Content-Type': 'application/json' },
success: function (data) {
res(data)
},
error: function (xhr, type, errorThrown) {
rej(errorThrown)
},
})
} catch (e) {
rej(e)
}
})
}
export default {
get (url, params, options) {
return promiseAjax(url, 'get', params, options)
},
post (url, params, options) {
return promiseAjax(url, 'post', params, options)
},
}
收起阅读 »

分享一下Uniapp安卓调用 微信一次性订阅 消息的方法
【前提】:Uniapp已经配置了微信分享的相关东西;暂时只写了安卓了,后面把iOS的也补充一下
实际代码:
var SubscribeMessage = plus.android.importClass("com.tencent.mm.opensdk.modelbiz.SubscribeMessage");
var subsMessageReq = new SubscribeMessage.Req();
subsMessageReq.plusSetAttribute("scene", 1234); // 随便一个整数,0-10000以内
subsMessageReq.plusSetAttribute("templateID", "123"); // 在微信开放后台,可以查看自己应用的APPID对应的templateID
var IWXAPI = plus.android.importClass("com.tencent.mm.opensdk.openapi.IWXAPI");
var WXAPIFactory = plus.android.importClass("com.tencent.mm.opensdk.openapi.WXAPIFactory");
var wxapi = WXAPIFactory.createWXAPI(plus.android.runtimeMainActivity().getContext(), "appid"); // appid是你自己微信的appid
wxapi.sendReq(subsMessageReq);
具体有什么用途,可以看下官方的操作就好了,这个是NJS的东西,顺便分享一下
【前提】:Uniapp已经配置了微信分享的相关东西;暂时只写了安卓了,后面把iOS的也补充一下
实际代码:
var SubscribeMessage = plus.android.importClass("com.tencent.mm.opensdk.modelbiz.SubscribeMessage");
var subsMessageReq = new SubscribeMessage.Req();
subsMessageReq.plusSetAttribute("scene", 1234); // 随便一个整数,0-10000以内
subsMessageReq.plusSetAttribute("templateID", "123"); // 在微信开放后台,可以查看自己应用的APPID对应的templateID
var IWXAPI = plus.android.importClass("com.tencent.mm.opensdk.openapi.IWXAPI");
var WXAPIFactory = plus.android.importClass("com.tencent.mm.opensdk.openapi.WXAPIFactory");
var wxapi = WXAPIFactory.createWXAPI(plus.android.runtimeMainActivity().getContext(), "appid"); // appid是你自己微信的appid
wxapi.sendReq(subsMessageReq);
具体有什么用途,可以看下官方的操作就好了,这个是NJS的东西,顺便分享一下
收起阅读 »
uni.getLocation()定位小BUG
APP模式开启了geocode
成功回调里 log可以正确打印出地址
但是在回调里无法赋值把res.XX 渲染到{{}}里
最后用缓存解决!
希望能顺手解决一下!
APP模式开启了geocode
成功回调里 log可以正确打印出地址
但是在回调里无法赋值把res.XX 渲染到{{}}里
最后用缓存解决!
希望能顺手解决一下!

uniapp--悬浮可拖动按钮-实现思路
<template>
<view class="content">
<view :style="{'transform':'translate3d('+xMove+'px,'+yMove+'px,0)'}" class="touch" @touchstart="handleStart" @touchmove="handleMove" @touchend="handleEnd">↑</view>
</view>
</template>
<script>
var curPoint = {
x: 0,
y: 0
}; // 记录原点
var startPoint = {};
// 标志位(只触发点击事件按,并没有移动-就不必触发end事件)
var isTouchMove = false;
export default {
data() {
return {
xMove: 0,
yMove: 0
};
},
onLoad() {},
mounted() {
// 想通过获取节点来实现动态移动--这条路没有走通
// let view = uni.createSelectorQuery().in(this);
// view.select('.touch').boundingClientRect(data => {
// console.log(data)
// data.top = 100
// }).exec();
// let view = uni.createSelectorQuery().select('.touch');
// view.fields({rect: true},data => {
// console.log(data)
// data.top = 100
// }).exec();
},
methods: {
handleStart(ev) {
// console.log('start',ev);
// 记录一开始手指按下的坐标
var touch = ev.changedTouches[0];
startPoint.x = touch.pageX;
startPoint.y = touch.pageY;
},
handleMove(ev) {
// console.log('move',ev);
// 防止页面高度很大,出现滚动条,不能移动-默认拖动滚动条事件
ev.preventDefault();
isTouchMove = true;
var touch = ev.changedTouches[0];
var diffPonit = {}; // 存放差值
var movePonit = {
// 记录移动的距离
x: 0,
y: 0
};
diffPonit.x = touch.pageX - startPoint.x;
diffPonit.y = touch.pageY - startPoint.y;
// 移动的距离 = 差值 + 当前坐标点
movePonit.x = diffPonit.x + curPoint.x;
movePonit.y = diffPonit.y + curPoint.y;
this.move(movePonit.x, movePonit.y);
},
handleEnd(ev) {
// console.log('end', ev);
if (!isTouchMove) return;
// 更新坐标原点
var touch = ev.changedTouches[0];
curPoint.x += touch.pageX - startPoint.x;
curPoint.y += touch.pageY - startPoint.y;
// 重置
isTouchMove = false;
},
move(x, y) {
x = x || 0; // 没有传就是0
y = y || 0;
this.xMove = x;
this.yMove = y;
// translate3d (tx,ty,tz) 在X轴偏移tx,在Y轴偏移ty,在Z轴偏移tz,单位px
}
}
};
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.touch {
position: fixed;
right: 20px;
bottom: 20px;
width: 45px;
height: 45px;
line-height: 45px;
text-align: center;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 50%;
color: #fff;
font-size: 30px;
/* 使用transform: translate3d 处理性能高 GUP */
}
</style>
<template>
<view class="content">
<view :style="{'transform':'translate3d('+xMove+'px,'+yMove+'px,0)'}" class="touch" @touchstart="handleStart" @touchmove="handleMove" @touchend="handleEnd">↑</view>
</view>
</template>
<script>
var curPoint = {
x: 0,
y: 0
}; // 记录原点
var startPoint = {};
// 标志位(只触发点击事件按,并没有移动-就不必触发end事件)
var isTouchMove = false;
export default {
data() {
return {
xMove: 0,
yMove: 0
};
},
onLoad() {},
mounted() {
// 想通过获取节点来实现动态移动--这条路没有走通
// let view = uni.createSelectorQuery().in(this);
// view.select('.touch').boundingClientRect(data => {
// console.log(data)
// data.top = 100
// }).exec();
// let view = uni.createSelectorQuery().select('.touch');
// view.fields({rect: true},data => {
// console.log(data)
// data.top = 100
// }).exec();
},
methods: {
handleStart(ev) {
// console.log('start',ev);
// 记录一开始手指按下的坐标
var touch = ev.changedTouches[0];
startPoint.x = touch.pageX;
startPoint.y = touch.pageY;
},
handleMove(ev) {
// console.log('move',ev);
// 防止页面高度很大,出现滚动条,不能移动-默认拖动滚动条事件
ev.preventDefault();
isTouchMove = true;
var touch = ev.changedTouches[0];
var diffPonit = {}; // 存放差值
var movePonit = {
// 记录移动的距离
x: 0,
y: 0
};
diffPonit.x = touch.pageX - startPoint.x;
diffPonit.y = touch.pageY - startPoint.y;
// 移动的距离 = 差值 + 当前坐标点
movePonit.x = diffPonit.x + curPoint.x;
movePonit.y = diffPonit.y + curPoint.y;
this.move(movePonit.x, movePonit.y);
},
handleEnd(ev) {
// console.log('end', ev);
if (!isTouchMove) return;
// 更新坐标原点
var touch = ev.changedTouches[0];
curPoint.x += touch.pageX - startPoint.x;
curPoint.y += touch.pageY - startPoint.y;
// 重置
isTouchMove = false;
},
move(x, y) {
x = x || 0; // 没有传就是0
y = y || 0;
this.xMove = x;
this.yMove = y;
// translate3d (tx,ty,tz) 在X轴偏移tx,在Y轴偏移ty,在Z轴偏移tz,单位px
}
}
};
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.touch {
position: fixed;
right: 20px;
bottom: 20px;
width: 45px;
height: 45px;
line-height: 45px;
text-align: center;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 50%;
color: #fff;
font-size: 30px;
/* 使用transform: translate3d 处理性能高 GUP */
}
</style>
收起阅读 »

自定义底部导航条刘海机型屏幕出现黑色横条遮挡问题,适配ihone x,ihone 11 和12的机型
自定义底部导航条刘海机型屏幕出现黑色横条遮挡问题,适配ihone x,ihone 11 和12的机型
修改前情况
修改后情况
打开项目文件 app.vue
app.vue
1.增加全局参数
globalData: {
isIphoneXup:false,//是否iphonex以及以上的版本
},
2.增加获取机型
onShow: function() {
console.log('App Show');
var that = this
// 获取设备机型
wx.getSystemInfo({
success: res=>{
console.log(res)
let model = res.model;
if (/iphone\sx/i.test(model) || (/iphone/i.test(model) && /unknown/.test(model))|| /iphone\s11/i.test(model)){
console.log("是x以上")
that.globalData.isIphoneXup = true;
}else{
console.log("不是x以上")
that.globalData.isIphoneXup = false;
}
}
})
},
3.增加全局样式,下补白
.isIPXup{
padding-bottom: 68rpx !important;
}
在需要引入的页面,如底部导航条的组件页面
mounted() {
//获取当前设备机型
this.isIphoneXup = app.globalData.isIphoneXup?app.globalData.isIphoneXup:false
// console.log(this.tabBar.list)
},
<view class="blockfixed" :class="isIphoneXup?'isIPXup':''"></view>
自定义底部导航条刘海机型屏幕出现黑色横条遮挡问题,适配ihone x,ihone 11 和12的机型
修改前情况
修改后情况
打开项目文件 app.vue
app.vue
1.增加全局参数
globalData: {
isIphoneXup:false,//是否iphonex以及以上的版本
},
2.增加获取机型
onShow: function() {
console.log('App Show');
var that = this
// 获取设备机型
wx.getSystemInfo({
success: res=>{
console.log(res)
let model = res.model;
if (/iphone\sx/i.test(model) || (/iphone/i.test(model) && /unknown/.test(model))|| /iphone\s11/i.test(model)){
console.log("是x以上")
that.globalData.isIphoneXup = true;
}else{
console.log("不是x以上")
that.globalData.isIphoneXup = false;
}
}
})
},
3.增加全局样式,下补白
.isIPXup{
padding-bottom: 68rpx !important;
}
在需要引入的页面,如底部导航条的组件页面
mounted() {
//获取当前设备机型
this.isIphoneXup = app.globalData.isIphoneXup?app.globalData.isIphoneXup:false
// console.log(this.tabBar.list)
},
<view class="blockfixed" :class="isIphoneXup?'isIPXup':''"></view>