uni-app踩坑集合(app)

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('有朋自远方来,不亦乐乎?')
  }

10.应用语音播报全局系统提示框
uni-app踩坑集合(app)_第1张图片

// 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>

你可能感兴趣的:(uni-app,android)