1.自定义启动页图片
manifest.json文件配置如下
"splashscreen" : {
"androidStyle" : "default",
"android" : {
"hdpi" : "xxxx.png",
"xhdpi" : "xxxx.png",
"xxhdpi" : "xxxx.png"
}
}
2.应用首次开启温馨提示
manifest.json文件配置如下
"privacy" : {
"prompt" : "template",
"template" : {
//prompt取值为template时有效,用于配置模板提示框上显示的内容
"title" : "温馨提示",
"message" : " 欢迎使用App,在你使用时,需要连接数据网络或者WIFI,产生的流量请咨询当地运营商。非常重视你的隐私保护和个人信息保护。在使用App服务前,请认真阅读《用户服务协议》及《隐私政策》,全部条款。你同意并接受全部条款后开始使用我们的服务
",
"buttonAccept" : "同意并继续", //继续下一步,进入首页
"buttonRefuse" : "不同意" //退出下载
}
},
3.应用首次开启授权应用权限
manifest.json文件配置如下
/* 申请获取手机存储权限 */
"permissionExternalStorage" : {
"request" : "always",
"prompt" : "应用保存运行状态等信息,需要获取读写手机存储(系统提示为访问设备上的照片、媒体内容和文件)权限,请允许。"
},
"permissionPhoneState" : {
"request" : "always",
"prompt" : "为保证您正常、安全地使用,需要获取设备识别码(部分手机提示为获取手机号码)使用权限,请允许。"
}
4.应用调用权限
manifest.json文件配置如下
"android" : {
"permissions" : [
"\" android.hardware.camera\"/>",
]
}
5.应用退出
Logout(){
// #ifdef APP-PLUS
plus.runtime.quit()
// #endif
}
6.应用缓存获取及清空
/**
currentSize-缓存文字
*/
// 获取本地缓存大小
getStorageSize() {
let that = this
// #ifdef APP-PLUS
plus.cache.calculate(function (size) {
let sizeCache = parseInt(size)
if (sizeCache == 0) {
that.currentSize = '0B'
} else if (sizeCache < 1024) {
that.currentSize = sizeCache + 'B'
} else if (sizeCache < 1048576) {
that.currentSize = (sizeCache / 1024).toFixed(2) + 'KB'
} else if (sizeCache < 1073741824) {
that.currentSize = (sizeCache / 1048576).toFixed(2) + 'MB'
} else {
that.currentSize = (sizeCache / 1073741824).toFixed(2) + 'GB'
}
})
// #endif
},
// 清理缓存
clearStorage() {
let that = this
// #ifdef APP-PLUS
let os = plus.os.name
if (os == 'Android') {
let main = plus.android.runtimeMainActivity()
let sdRoot = main.getCacheDir()
let files = plus.android.invoke(sdRoot, 'listFiles')
let len = files.length
console.log(files, len)
for (let i = 0; i < len; i++) {
let filePath = '' + files[i] // 没有找到合适的方法获取路径,这样写可以转成文件路径
plus.io.resolveLocalFileSystemURL(
filePath,
function (entry) {
if (entry.isDirectory) {
entry.removeRecursively(
function (entry) {
//递归删除其下的所有文件及子目录
that.files = []
uni.showToast({
title: '清除成功',
duration: 2000,
})
that.getStorageSize() // 重新计算缓存
},
function (e) {
console.log(e.message)
}
)
} else {
entry.remove()
}
},
function (e) {
console.log('文件路径读取失败')
}
)
}
} else {
// ios
plus.cache.clear(function () {
uni.showToast({
title: '清除成功',
duration: 2000,
})
that.getStorageSize()
})
}
// #endif
},
7.应用版本更新
思路:
1.web管理端上传值后台应用包、版本号、是否强制更新等字段
2.应用调用后台接口获取应用包、版本号、是否强制更新等字段
3.进度条展示
4.比较本应用版本号和后台接口返回是否调用下载及安转
//步骤3进度条
模板
<view class="progress-container" v-if="showdownLine">
<view class="progress-box">
<view class="text">新版本下载中,请稍后......</view>
<progress :percent="downloadNum" show-info stroke-width="3" />
</view>
</view>
样式
.progress-container {
position: fixed;
top: 0;
left: 0;
z-index: 99;
background: rgba(0, 0, 0, 0.2);
width: 750rpx;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
.progress-box {
background: #ffffff;
border-radius: 20rpx;
padding: 30rpx;
.text {
margin-bottom: 20rpx;
}
}
}
//步骤4: 获取本应用版本号
getversion() {
let that = this
// #ifdef APP-PLUS
plus.runtime.getProperty(plus.runtime.appid, (info) => {
that.versionnumber = info.version
})
// #endif
},
// 检测版本更新
checkUpdates(val) {
// 待更新版本
const currentVersion = val.versionNo
// 更新地址
let androidUrl = val.installationPackageUrl
// 是否强制更新 isMust 0.否 1.强制更新
let showCancel = val.isMust ? true : false
// 比较版本是否不同 当前版本:plus.runtime.version
const localVersion = this.versionnumber.split('.')
let current = currentVersion.split('.')
// 默认是同一个版本,不需要更新
let flag = false
current.forEach((item, i) => {
if (item !== localVersion[i]) {
// 检测到版本不同,需要更新
flag = true
}
})
if (flag) {
uni.showModal({
// 更新提醒
title: '发现新版本,是否更新',
content: '待更新版本号:' + currentVersion,
success: (res) => {
if (res.confirm) {
this.doUpData(androidUrl)
this.showdownLine = true
} else if (res.cancel) {
// 不更新强制退出app
if (showCancel) {
// #ifdef APP-PLUS
plus.runtime.quit()
// #endif
}
}
},
})
} else {
this.$u.toast('无更新')
}
},
doUpData(Url) {
const downloadTask = uni.downloadFile({
//执行下载
url: Url, //下载地址
timeout: 1000 * 30, //30秒超时时间
success: (downloadResult) => {
//下载成功
this.showdownLine = false
if (downloadResult.statusCode == 200) {
// #ifdef APP-PLUS
plus.runtime.install(
//安装软件
downloadResult.tempFilePath,
{
force: true,
},
function (res) {
plus.runtime.restart()
}
)
// #endif
}
},
fail: (err) => {
this.showdownLine = false
this.$u.toast(err.errMsg)
console.log(err)
},
complete: (com) => {
console.log(com)
},
})
// 下载进度
downloadTask.onProgressUpdate((res) => {
if (res.progress > 0) {
this.showdownLine= true
}
this.downloadNum = res.progress
// console.log('下载进度' + res.progress);
// console.log('已经下载的数据长度' + res.totalBytesWritten);
// console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
})
},
8.应用根据角色动态tabbar且有默认角色
思路:
1.开启page.json中tabbar自定义-> "custom": true,
2.封装tabbar页面(动态的tabbar数据源)
3.tabbar页面隐藏自带tabbar->uni.hideTabBar({})
4.引用封装tabbar页面
注意:动态tabbar使用uni.reLaunch做页面跳转
//步骤2: 封装tabbar页面
<template>
<view class="tab-bar">
<view class="content">
<view
class="one-tab"
v-for="(item, index) in tabBarList"
:key="index"
@click="selectTabBar(item.pagePath)"
>
<view>
<view class="tab-img">
<image
v-if="routePath === item.pagePath"
class="img"
:src="item.selectedIconPath"
></image>
<image v-else class="img" :src="item.iconPath"></image>
</view>
</view>
<view class="tit">{{ item.text }}</view>
</view>
</view>
</view>
</template>
<script>
import { cargoownertabbar, drivertabbar, carriertabbar } from 'common/tabbar.js'
export default {
name: 'C_tabbar',
props: {
// 当前页面路径
routePath: {
type: String,
required: true,
},
},
data() {
return {
tabBarList: [],
}
},
methods: {
selectTabBar(path) {
console.log(path)
uni.reLaunch({
url: '/' + path,
})
},
},
watch: {
/*
监听进入应用的身份,如果为空为游客模式,登录后修改该值
*/
'$store.state.identity': {
handler(newVal, oldVal) {
if (newVal) {
if (newVal == '4') {
this.tabBarList = cargoownertabbar
} else if (newVal == '3') {
this.tabBarList = drivertabbar
} else if (newVal == '2') {
this.tabBarList = carriertabbar
} else {
}
} else {
this.tabBarList = drivertabbar
}
},
immediate: true,
},
},
}
</script>
<style lang="scss">
.tab-bar {
position: fixed;
height: 100rpx;
bottom: 0;
left: 0;
width: 100vw;
padding: 12rpx 20rpx;
padding-bottom: calc(10rpx + constant(safe-area-inset-bottom));
padding-bottom: calc(10rpx + env(safe-area-inset-bottom));
background: #fff;
border-top: 1rpx solid #00000054;
z-index: 1;
.content {
display: flex;
.one-tab {
display: flex;
flex-direction: column;
align-items: center;
width: 50%;
background: #fff;
.tab-img {
width: 50rpx;
height: 50rpx;
.img {
width: 100%;
height: 100%;
}
}
.tit {
font-size: 36rpx;
transform: scale(0.7);
}
}
}
}
</style>
9.应用语音播报(文字转语音)
/**
*1.创建播放对象
*2.播放url(文字转语音开放api:百度、搜狗、有道)
*百度参数:lan 语言类型(lan=en 英文、lan = zh 中文)、ie 文字编码方式、spd 语速(1-9的数字,数字越大,语速越快)、text 要转换的文本
*搜狗参数:lang 语言类型(lang=en 英文、lang= zh 中文)、speed 语速(1-15的数字,数字越大,语速越快)、text 要转换的文本、speaker 语音类型 1-6的数字
*有道参数:le 语言类型(le=en 英文、le= zh 中文)、word要转换的文本
*/
methods: {
ttspeech(text) {
text= text.replace(/\s*/g,"");
var music = null
music = uni.createInnerAudioContext() //创建播放器对象
// music.src = `http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=4&text=${text}`//百度
// music.src = `https://fanyi.sogou.com/reventondc/synthesis?text=${text}&speed=1&lang=zh-CHS&from=translateweb&speaker=6`//搜狗
music.src = `http://tts.youdao.com/fanyivoice?word=${text}&le=zh&keyfrom=speaker-target` //有道
music.play() //执行执行播放
music.onEnded(() => {
//音频播放结束
music = null
})
},
},
onShow: function (e) {
this.ttspeech('有朋自远方来,不亦乐乎?')
}
// show_modal/index.js
export class show_model {
constructor(option = {}) {
this.bodyModel = null;
this.cancelModel = null;
this.confirmModel = null;
this.pageHeight = uni.getSystemInfoSync().screenHeight;
this.pageWidth = uni.getSystemInfoSync().screenWidth;
let opacity = option.opacity || 0.4;
let model_tit = option.title || '温馨提示';
let model_content = option.content || "内容"
let clickEvent = option.IsclickEvent || false;
let cancelVal = option.cancelVal || '取消';
let confirmVal = option.confirmVal || '确认';
let cancelColor = option.cancelColor || '#fff'; // 取消
let confirmColor = option.confirmColor || '#fff'; // 确认
let delCancel = option.delCancel || false;
let align = option.align || "center";
let fn = () => { };
this.$event = option.$event || fn;
let backOff = option.backOff || false;
//#ifdef APP-PLUS
this.creatView({ height: `${this.pageHeight}px`, top: 0 }, opacity, clickEvent, { 'tit': model_tit, 'content': model_content, cancelVal, confirmVal, confirmColor, cancelColor, delCancel, align })
if (!backOff) {
this.backbtn();
}
//#endif
}
backbtn () {
let that = this;
plus.key.addEventListener('backbutton', function (e) {
that.hide();
}, false)
}
//生成提示框view
creatView (style, opa, clickEvent, modelInfo) {
style = {
left: '0px',
top: '0px',
width: '100%',
...style
}
let platform = plus.os.name.toLowerCase();
let view = new plus.nativeObj.View('showModalView', style);
let width = 500;
let height = 100;
let titleHeight = 0;
let contentHeight = 20;
let startTop = 0;
let startLeft = (this.pageWidth - width) / 2;
let titleTop = 0;
let contentTop = titleTop + 30;
let lineTop = startTop + height - 40;
let buttonHeight = 40;
let halfWidth = width / 2;
let halfWidthForGlobal = width - 140;;
if (platform == "ios") {
view.draw([
{ tag: 'rect', id: 'modal', color: `rgba(0,0,0,${opa})`, position: { top: '0px', left: '0px', width: '100%', height: '100%' } },
{ tag: 'rect', id: 'content', rectStyles: { borderWidth: '2px', radius: '8px', color: `rgba(36,34,56,1)` }, position: { top: startTop + 'px', left: startLeft + 'px', width: width + 'px', height: height + 'px' } },
{ tag: 'font', id: 'title', text: modelInfo.tit, textStyles: { size: '16px', color: '#fff' }, position: { top: titleTop + 'px', left: startLeft + 'px', width: width + 'px', height: titleHeight + 'px' } },
{ tag: 'font', id: 'text', text: modelInfo.content, textStyles: { size: '14px', color: '#fff', whiteSpace: 'normal', align: modelInfo.align }, position: { top: contentTop + 'px', left: startLeft + 'px', width: width + 'px', height: contentHeight + 'px' } },
{ tag: 'rect', id: 'line', color: 'rgba(255,255,255,0.3)', position: { top: lineTop + 'px', left: startLeft + 'px', width: width + 'px', height: '0.5px' } },
{ tag: 'rect', id: 'line2', color: 'rgba(255,255,255,0.3)', position: { top: lineTop + 'px', left: +halfWidthForGlobal + 'px', width: modelInfo.delCancel ? '0px' : '0.5px', height: modelInfo.delCancel ? '0px' : buttonHeight + 'px' } }
]);
} else {
view.draw([
{ tag: 'rect', id: 'modal', color: `rgba(0,0,0,${opa})`, position: { top: '0px', left: '0px', width: '100%', height: '100%' } },
{ tag: 'rect', id: 'content', rectStyles: { borderWidth: '2px', radius: '8px', color: `rgba(36,34,56,1)` }, position: { top: startTop + 'px', left: startLeft + 'px', width: width + 'px', height: height + 'px' } },
{ tag: 'font', id: 'title', text: modelInfo.tit, textStyles: { size: '16px', color: '#fff' }, position: { top: titleTop + 'px', left: startLeft + 'px', width: width + 'px', height: titleHeight + 'px' } },
{ tag: 'font', id: 'text', text: modelInfo.content, textStyles: { size: '14px', color: '#fff', whiteSpace: 'normal', align: modelInfo.align }, position: { top: contentTop + 'px', left: startLeft + 'px', width: width + 'px', height: contentHeight + 'px' } },
{ tag: 'rect', id: 'line', color: 'rgba(255,255,255,0.3)', position: { top: lineTop + 'px', left: startLeft + 'px', width: width + 'px', height: '0.5px' } },
{ tag: 'rect', id: 'line2', color: 'rgba(255,255,255,0.3)', position: { top: lineTop + 'px', left: halfWidthForGlobal + 'px', width: modelInfo.delCancel ? '0px' : '0.5px', height: modelInfo.delCancel ? '0px' : buttonHeight + 'px' } }
]);
}
var num = 0.55;
if (platform == "ios") {
num = 0.57
}
if (!modelInfo.delCancel) {
// 取消
let viewCancel = new plus.nativeObj.View('cancel', { width: halfWidth + 'px', height: buttonHeight + 'px', top: lineTop + 'px', left: startLeft + 'px', backgroundColor: 'rgba(255,255,255,0)' });
viewCancel.draw([
{ tag: 'font', id: 'cancel', text: modelInfo.cancelVal, textStyles: { color: modelInfo.cancelColor, size: '14px' } },
]);
viewCancel.addEventListener("click", (e) => {
this.$event({ res: false, types: 'cancel' });
this.hide();
}, false);
this.cancelModel = viewCancel;
}
// 确认
let viewconfirm = new plus.nativeObj.View('confirm',
{
width: '100px',
height: buttonHeight + 'px',
top: lineTop + 'px',
left: halfWidthForGlobal + 'px',
backgroundColor: '#1890FF',
},
);
viewconfirm.draw([
{ tag: 'font', id: 'confirm', text: modelInfo.confirmVal, textStyles: { color: modelInfo.confirmColor, size: '14px' } },
]);
viewconfirm.addEventListener("click", (e) => {
this.$event({ res: true, types: 'confirm' });
this.hide();
}, false);
//点击蒙布
if (clickEvent) {
view.addEventListener("click", (e) => {
this.$event({ res: true, types: 'cover' });
this.hide();
}, false);
}
this.bodyModel = view;
this.confirmModel = viewconfirm;
}
showModalAnimationClose () {
var options = { type: 'pop-out', duration: 300 };
plus.nativeObj.View.startAnimation(options, { view: this.bodyModel }, { view: this.cancelModel }, { view: this.viewconfirm }, function () {
console.log('plus.nativeObj.View.startAnimation动画结束');
// 关闭原生动画
plus.nativeObj.View.clearAnimation();
});
}
showModalAnimationOpen () {
var options = { type: 'pop-in', duration: 1000 };
plus.nativeObj.View.startAnimation(options, { view: this.bodyModel }, { view: this.cancelModel }, { view: this.viewconfirm }, function () {
console.log('plus.nativeObj.View.startAnimation动画结束');
// 关闭原生动画
plus.nativeObj.View.clearAnimation();
});
}
show () {
this.showModalAnimationOpen();
this.bodyModel.show();
if (this.cancelModel) {
this.cancelModel.show();
}
this.confirmModel.show();
}
hide () {
this.showModalAnimationClose();
this.bodyModel.hide();
if (this.cancelModel) {
this.cancelModel.hide();
}
this.confirmModel.hide();
}
}
export default show_model
// show_modal/xt_show_modal.js
import show_modal from './index.js'
const xt_show_modal = {
install: function (Vue) {
const show_modal_fun = function (op = {}) {
//#ifdef APP-PLUS
return new Promise((resolve, reject) => {
let ssm = new show_modal({
...op,
$event: function (e) {
if (e.res) {
resolve(e);
} else {
reject(e);
}
}
});
ssm.show();
Vue.prototype.$hide = function () {
ssm.hide();
}
})
//#endif
// 适应H5
//#ifdef H5
var promise = uni.showModal({
title: op.title,
content: op.content,
showCancel: !op.delCancel,
cancelText: op.cancelVal,
confirmText: op.confirmVal,
});
return new Promise((resolve, reject) => {
promise.then(data => {
var [err, res] = data;
if (res.confirm) {
resolve()
} else {
reject();
}
})
})
//#endif
}
// $showModal挂载到uni对象上
uni.$showModal = show_modal_fun
Vue.prototype.$showModal = show_modal_fun
}
};
export default xt_show_modal;
// main.js
// 自定义showModal组件
import xt_show_modal from './components/show_modal/xt_show_modal.js'
Vue.use(xt_show_modal);
app.vue
//播报语音和全局提示
ttspeech(text) {
uni
.$showModal({
title: '', //可选,不填则不显示
content: '货源推荐,西安未央到西安碑林,澳大利亚超特粉,160元',
delCancel: true,
IsclickEvent: true,
confirmVal: '抢单', // 可选
})
.then((res) => {
// 点击确认按钮点击事件
console.log('点击确认按钮点击事件', res)
})
.catch((res) => {
// 点击取消按钮点击事件
})
setTimeout(() => {
this.$hide()
}, 4000)
// text = text.replace(/\s*/g, '')
// var music = null
// music = uni.createInnerAudioContext() //创建播放器对象
// // music.src = `http://tts.baidu.com/text2audio?lan=zh&ie=UTF-8&spd=4&text=${text}`//百度
// // music.src = `https://fanyi.sogou.com/reventondc/synthesis?text=${text}&speed=1&lang=zh-CHS&from=translateweb&speaker=6`//搜狗
// music.src = `http://tts.youdao.com/fanyivoice?word=${text}&le=zh&keyfrom=speaker-target` //有道
// music.play() //执行执行播放
// music.onEnded(() => {
// //音频播放结束
// music = null
// })
},
11.web-view缩放
<template>
<view class="wrap">
<web-view :src="link"></web-view>
</view>
</template>
<script>
export default {
components: {},
data() {
return {
link: 'https://xxxxx.com/document/driver_privacyagreement.html',
}
},
onReady() {
var currentWebview = this.$scope.$getAppWebview() //获取当前页面的webview对象
// console.log("currentWebview",currentWebview)
setTimeout(function () {
const wv = currentWebview.children()[0] //取出当前webview实例
wv.setStyle({
scalable: true, //添加样式,启动缩放
})
wv.evalJS(`
var metaEl = document.createElement('meta')
metaEl.setAttribute('name','viewport')
metaEl.setAttribute('content', 'width=device-width, initial-scale=1,user-scalable=yes')
document.head.appendChild(metaEl)
`)
}, 1000) //如果是页面初始化调用时,需要延时一下
// #endif
},
}
</script>
<style lang="scss" scoped></style>