快应用开发常见问题及解决方案

快应用 Feb 24, 2019

快应用是移动互联网新型应用生态,与手机系统深度整合,为用户提供更加场景化的体验。具备传统 APP 完整的应用体验,但无需安装、即点即用。快应用是基于手机硬件平台的新型应用形态,由国内十大手机厂商基于硬件平台共同推出,其标准是由主流手机厂商组成的快应用联盟联合制定。这里记录下在快应用开发中,涉及的常见问题及其对应解决方案;同时也会给出如何更好开发快应用的一些建议。

温馨提醒:如果您目前有涉及进行快应用开发,那么您不妨看下快应用脚手架,为优雅而生一文,其中将开发所遇到的一些问题、以及开发体验都作了很大程度上的优化,相信会给你带来帮助(另外, Github 上的 awesome-quickapp 仓库:云集最新快应用相关教程文章、开发资源、项目案例及新闻动态;相信也会给您更好进行快应用开发,提供更多帮助)。

快应用引擎相关

快应用生命周期函数

  • 现有的APP生命周期函数有: onCreate, onDestroy
  • 现有的页面级组件生命周期函数:onCreate、onInit、onReady、onShow、onHide、onDestroy(onBackPress、onMenuPress)
  • 已有的自定义组件生命周期函数: onCreate、onInit、onReady、onDestroy(onDestroy 只会在页面销毁的时候触发,用 if 指令卸载无法触发)

快应用的 $app、$def、$data 以及 global

在快应用中,暴露了 $app 对象;此对象下有暴露出 $def$data等字段:

  • $def: 使用 this.$app.$def 获取在 app.ux 中暴露的对象;
  • $data:使用 this.$app.$data 获取在 manifest.json 的 config.data 中声明的全局数据;

但需要注意的是:直接挂在于 this 上,需通过 this.$app 来取;挂在于 this.$def 上,才可通过 this.$app.$def 来取,二者不可混淆。

// app.ux
import device from '@system.device'
const hook2global = global.__proto__ || global
hook2global.$apis = $apis

  < script >
	export default {
  $deviceInfo: {},
  $xDeviceInfo: {},
  async onCreate() {
    this.$def.$deviceInfo = await this.getInfo()
    this.$xDeviceInfo = await this.getInfo()
  },
  async getInfo() {
    return new Promise((resolve, reject) => {
      device.getInfo({
        success: ret => {
          resolve(ret)
        },
        fail: err => {
          console.log(err)
        }
      })
    })
  }
}
</script >

如上示例代码,在其他页面代码中,this.$app.$def.$deviceInfo、 this.$app.$xDeviceInfo 这两种调用方式是期待的写法;如果混淆调用,得到的结果则是 undefined

而挂在于 global 的变量(如 $apis ),可通过 global.$apis 或直接 $apis 来调用;但如果在 DOM 结构中,不可直接使用,因为其默认主题是页面级 this,所以 Toolkit 编译出的结果就会是 this.$apis or this.global.$apis,如此就不能达到预期;在页面属性中定义声明下即可,如下代码示例:

<script>
  export default {
    $apis: $apis // or global.$apis
  }
<script>

如何解决快应用 Input 失去焦点,输入法不收起来问题

目前(1050-)可以解决的办法是,在空白区域,添加事件,注入如下逻辑:

this.$element('yourInputId').focus({focus: false})

如何解决快应用 textarea 无法清空数据问题

快应用(version <= 1030)目前存在 textarea 无法清空数据问题,目前只能采取 Hack 的办法解决,即在需要清除时候 this.$delete 掉该绑定的值,onchange 回调中再通过 this.$set 将数据属性添加回去,使得可以正常工作;

<textarea onchange='handleChange' placeholder="{{placeholder}}" value="{{contentValue}}" id="keyborder"></textarea>
<input class="input" type="button" onclick="onHandleBtnClick" value="处理"></input>
<script>
export default {
  handleChange(response) {
    console.log(JSON.stringify(response, null, 2))

    // 以 Hack 的方式解决无法清空 textarea 输入数据@18-12-06;
    this.$set('contentValue', response.text)
  },
  onHandleBtnClick() {
    // Here ....... 处理你的数据;

    // 以 Hack 的方式解决无法清空 textarea 输入数据@18-12-06;
    this.$delete('contentValue')
  }
}
</script>

快应用中如何使用「字体图标」

在应用中,可以使用字体图标icomoon,可以帮着有更好的方案来展示应用图标;在快应用中,可以直接在 dom 中使用,如下示例。但,对于定义在变量中的字体编码,则需要借助 unescape 做一层转换。

<template>
   	<text class="font-icon" style="font-size: {{fontSize}}px;">&#xe900;</text>
	<text class="font-icon" style="font-size: {{fontSize}}px;">{{ iconCode }}</text>
	<text class="font-icon" style="font-size: {{fontSize}}px;">{{ unescapeFontIconCode(iconCode) }}</text>
</template>

<script>
export default {
  private: {
    fontSize: 100,
    iconCode: '&#xe900;'
  },
  unescapeFontIconCode(iconCode = '') {
	return unescape(iconCode.replace(/&#x/g, '%u').replace(/;/g, ''))
  }
}
</script>

<style>
@font-face {
  font-family: iconfont;
  src: url('./../../assets/fonts/icomoon.ttf');
}

.font-icon {
  font-family: iconfont;
}
</style>

如何动态处理修改快应用样式

鉴于些原因快应用 hap-toolkit 打包,无法对逻辑代码进行处理;而快应用引擎内部,也没有对逻辑代码中样式做很好的兼顾;所以,当需要动态处理修改快应用样式时,你需要对涉及的代码进行转义处理,如下代码示例(备注:在 1030 版本,组件的 style 属性,支持直接绑定 Object 或 String):

<template>
  <div class="wrapper-padding" style="{{ styleObj }}">
      <text>如何动态处理修改快应用样式</text>
  </div>
</template>


<script>
export default {
  protected: {
    styleObj: {},
    dynamicUrl: 'https://image.nicelinks.site/jpg/nice-links-039.jpg'
  },
  onReady() {
    this.styleObj = {
      backgroundColor: '#fe0',
      color: '#212121',
      backgroundImage: `${this.dynamicUrl}`
    }
  }
}
</script>

至于为何要这么处理,可以参看开发时,build 目录下所打包后的代码,hap-toolkit 是对样式进行了处理,只要逻辑层的代码修改,跟打包后的样式处置保持一致,那么就可以实现动态处理修改快应用样式;如上代码中对 background-image 的设置,就是为了兼容快应用内部打包适配(此解决方案针对 1040 及以前版本,未知快应用何时修复)。

如何从外部打开快应用:

从外部打开快应用,可以是从一个快应用,打开另一个快应用;也可以是从网页上打开快应用;实现此共功能,可以使用快应用提供的 deeplink 接口,其语法格式如下:

http://hapjs.org/app//[path][?key=value]
https://hapjs.org/app//[path][?key=value]
hap://app//[path][?key=value]

具体参数说明如下

package: 应用包名,必选;
path: 应用内页面的 path,可选,默认为首页;
key-value: 希望传给页面的参数,可选,可以有多个;

EG: hap://app/com.quickapp.nicelinks/?utm_source=quickapp-blog;

<a class="link" href="hap://app/com.quickapp.nicelinks">打开倾城之链快应用</a>

网页中打开「快应用」

嵌入如下 JS 代码:

<script type="text/javascript" src="//statres.quickapp.cn/quickapp/js/routerinline.min.js"></script>
<!-- 调起应用 -->
<script type="text/javascript">
  // 无需用户确认的调用方式,xxx.yyy.zzz 为包名
  appRouter("xxx.yyy.zzz", "/Home", { paramA: 1, paramB: '2' })
  // 需要用户确认的调用方式,xxx.yyy.zzz为包名
  appRouter('xxx.yyy.zzz', '/Home', { paramA: 1, paramB: '2' }, '显示给用户的应用名称');
  // Eg: 比如跳转至「倾城之链」,路径只能为 `/`,因为在 manifest.json 中 router 配置为:pages/Home;
  appRouter('com.quickapp.nicelinks', '/', { utm_source: 'github' });
</script>

需要额外注意的是,你所要跳转的快应用,如果在 manifest.json 中对路由加前缀,需要使用 path 字段予以“修正”,否则使用 deeplink 功能时候,将不能很好的工作。

"router": {
  "entry": "pages/Main",
  "pages": {
    "pages/Main": {
      "component": "index"
      // ✗ appRouter('com.quickapp.nicelinks', '/pages/Main' );
      // ✓ appRouter('com.quickapp.nicelinks', '/about' );
      "path": "/about"
    }
  }
}

快应用页面数据模型使用规范

页面文件中,如何正确使用 public, protected, private?

  • 若接收应用外部的数据覆盖,则设置为 public;
  • 若接收页面之间的数据覆盖,则设置为 protected;
  • 否则需设置为 private;

如何解决快应用“莫名”报错

在开发快应用时候,有时会遇到些“莫名”报错提示,比如下面这样:

TypeError: Cannot read property 'manifest' of null
at XPage.initMeta (:xxxx:yy)

从经验上看,由于些未知原因,导致程序出错,但没有给出具体错误原因,从而引起的抛出异常不精准(从错误提示上看,是因为在 initMeta 方法体中,某空对象调用了 manifest 属性);但,引起该问题的根本原因,就很多,比如 hap-toolkit 升级打包出错,或者该页面初始化前的代码存在异常等,都有可能导致该问题;这时能做的就是:仔细检查下代码以及打包(在官方修复之前)。

打包工具相关

如何升级 hap-toolkit<0.0.38 至最新:

  1. 将本地 hap-toolkit 升级至新版本如 0.2.0: yarn upgrade hap-toolkit@0.1.0;
  2. 运行 npx hap update --force 命令将本地配置升级(会新建 package.json, 原文件成 old package.json);
  3. 手动将 old package.json 中的自己的额外配置,同步至新的 package.json
  4. 将本地的 node_modulespackage-lock.json: rm -rf node_modules;
  5. 重新安装依赖即可:重新运行 yarn or npm i;

如何为快应用设置别名(alias)

在已有项目根目录下创建 config 文件夹,并在该文件夹下添加 webpack.config.js,然后注入类似如下代码即可:

const path = require('path')

module.exports = {
  postHook: function(webpackConf, options){
    const alias = Object.assign(webpackConf.resolve.alias || {}, {
      '@components': path.join(process.cwd(), 'src/components')
    })
    webpackConf.resolve.alias = alias
  }
}

如此,对于 import 自定义组件或方法,就会得到优化,而不用费神去关心相对路径(需要提醒的是:因为快应用现有设计缘故,别名不能作用于 Dom 结构以及 style);

<import name="HellorWorld" src="./../../components/HellorWorld"></import>
// 为快应用注入别名(alias)之后的写法
<import name="HellorWorld" src="@components/HellorWorld"></import>

@2019-02-24 于深圳.福田 Last Modify:2020-09-15


您可能会感兴趣的文章:

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.