Markup languages
前述のように、ミニアプリは単純な HTML ではなく、HTML のディレクトリで記述します。Vue.js のテキスト インターポレーションとディレクティブを扱ったことがある場合は、すぐに使いこなせるでしょう。しかし、同様のコンセプトは、それよりずっと前に XML 変換(XSLT)に存在していました。以下は WeChat の WXML のコードサンプルですが、コンセプトはすべてのミニアプリ プラットフォーム(Alipay の AXML、Baidu の Swan Element、ByteDance の TTML(DevTools では Bxml と呼ばれています)、Quick App の HTML)で同じです。Vue.js と同様に、基盤となるミニアプリ プログラミングのコンセプトは モデルビュービューモデル(MVVM)です。
データ バインディング
データ バインディングは、Vue.js のテキスト補間に対応しています。
<!-- wxml -->
<view>{{message}}</view>
// page.js
Page({
data: {
message: "Hello World!",
},
});
リストのレンダリング
リスト レンダリングは Vue.js の v-for
ディレクティブと同様に機能します。
<!-- wxml -->
<view wx:for="{{array}}">{{item}}</view>
// page.js
Page({
data: {
array: [1, 2, 3, 4, 5],
},
});
条件付きレンダリング
条件付きレンダリングは、Vue.js の v-if
ディレクティブと同様に機能します。
<!-- wxml -->
<view wx:if="{{view == 'one'}}">One</view>
<view wx:elif="{{view == 'two'}}">Two</view>
<view wx:else="{{view == 'three'}}">Three</view>
// page.js
Page({
data: {
view: "three",
},
});
テンプレート
命令的に HTML テンプレートの content
をクローニングする必要はなく、テンプレート定義にリンクする is
属性によって WXML テンプレートを宣言的に使用できます。
<!-- wxml -->
<template name="person">
<view>
First Name: {{firstName}}, Last Name: {{lastName}}
</view>
</template>
<template is="person" data="{{...personA}}"></template>
<template is="person" data="{{...personB}}"></template>
<template is="person" data="{{...personC}}"></template>
// page.js
Page({
data: {
personA: { firstName: "Alice", lastName: "Foo" },
personB: { firstName: "Bob", lastName: "Bar" },
personC: { firstName: "Charly", lastName: "Baz" },
},
});
スタイル設定
スタイル設定は CSS の各言語で行われます。WeChat は WXSS という名前です。Alipay では ACSS、Baidu では単に CSS、ByteDance では TTSS と呼ばれます。共通点は、レスポンシブ ピクセルで CSS を拡張することです。通常の CSS を記述する場合、デベロッパーは、幅とピクセル比が異なるさまざまなモバイル デバイスの画面に合わせて、すべてのピクセル単位を変換する必要があります。TTSS は、その下層として rpx
ユニットをサポートしています。つまり、ミニアプリはデベロッパーからジョブを引き継ぎ、指定された画面幅 750rpx
に基づいて単位を変換します。たとえば、画面幅が 393px
(デバイスのピクセル比が 2.75
)の Google Pixel 3a で、Chrome DevTools で検査すると、レスポンシブ 200rpx
は実際のデバイスで 104px
になります(393px / 750rpx * 200rpx ≈ 104px)。Android では、同じコンセプトが密度非依存ピクセルと呼ばれます。
/* app.wxss */
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0; /* ← responsive pixels */
box-sizing: border-box;
}
コンポーネント(後述)は Shadow DOM を使用しないため、ページで宣言されたスタイルはすべてのコンポーネントに適用されます。一般的なスタイルシート ファイル構成では、グローバル スタイル用のルート スタイルシートを 1 つと、ミニアプリの各ページに固有のページごとのスタイルシートを用意します。スタイルは、CSS の @import
ルールと同様に動作する @import
ルールを使用してインポートできます。HTML と同様に、スタイルはインラインで宣言することもできます(動的テキスト補間を含む)。before をご覧ください。
<view style="color:{{color}};" />
スクリプト
ミニアプリは、CommonJS や RequireJS を彷彿とさせるさまざまな構文を使用するモジュールのサポートを含む、JavaScript の「安全なサブセット」をサポートしています。JavaScript コードは eval()
経由で実行できず、new Function()
で関数を作成することもできません。スクリプトの実行コンテキストは、デバイスでは V8 または JavaScriptCore であり、シミュレータでは V8 または NW.js です。通常、ES6 以降の構文でコーディングできます。これは、ビルド ターゲットが古い WebView 実装のオペレーティング システムである場合、特定の DevTools によってコードが ES5 に自動的にトランスパイルされるためです(後述を参照)。スーパーアプリ プロバイダのドキュメントでは、スクリプト言語は JavaScript と混同せず、JavaScript とは異なることが明記されています。ただし、この記述は主にモジュールの動作方法、つまり標準の ES モジュールをまだサポートしていないことを指しています。
前述のように、ミニアプリ プログラミングのコンセプトは model-view-viewmodel(MVVM)です。ロジックレイヤとビューレイヤは異なるスレッドで実行されるため、長時間実行オペレーションによってユーザー インターフェースがブロックされることはありません。ウェブ用語では、ウェブワーカーで実行されるスクリプトと考えることができます。
WeChat のスクリプト言語は WXS、Alipay の SJS、ByteDance の SJS と呼ばれます。Baidu は、自社のサービスを参照する際に JS と表現しています。これらのスクリプトは、WeChat の <wxs>
など、特別な種類のタグを使用して含める必要があります。一方、クイックアプリでは、通常の <script>
タグと ES6 JS 構文が使用されます。
<wxs module="m1">
var msg = "hello world";
module.exports.message = msg;
</wxs>
<view>{{m1.message}}</view>
モジュールは、src
属性を介して読み込むことも、require()
を介してインポートすることもできます。
// /pages/tools.wxs
var foo = "'hello world' from tools.wxs";
var bar = function (d) {
return d;
};
module.exports = {
FOO: foo,
bar: bar,
};
module.exports.msg = "some msg";
<!-- page/index/index.wxml -->
<wxs src="./../tools.wxs" module="tools" />
<view>{{tools.msg}}</view>
<view>{{tools.bar(tools.FOO)}}</view>
// /pages/logic.wxs
var tools = require("./tools.wxs");
console.log(tools.FOO);
console.log(tools.bar("logic.wxs"));
console.log(tools.msg);
JavaScript ブリッジ API
ミニアプリとオペレーティング システムを接続する JavaScript ブリッジにより、OS の機能を使用できます(強力な機能へのアクセスをご覧ください)。また、便利なメソッドもいくつか用意されています。概要については、WeChat、Alipay、Baidu、ByteDance、Quick App のさまざまな API をご覧ください。
すべてのプラットフォームが、ウェブサイト caniuse.com から着想を得た名前の(文字どおり呼ばれる)canIUse()
メソッドを提供しているため、機能検出は単純明快です。たとえば、ByteDance の tt.canIUse()
では、API、メソッド、パラメータ、オプション、コンポーネント、属性のサポート チェックを行うことができます。
// Testing if the `<swiper>` component is supported.
tt.canIUse("swiper");
// Testing if a particular field is supported.
tt.canIUse("request.success.data");
更新
ミニアプリには標準化された更新メカニズムがありません(標準化の可能性に関するディスカッション)。すべてのミニアプリ プラットフォームにはバックエンド システムがあり、ミニアプリ デベロッパーはミニアプリの新しいバージョンをアップロードできます。すると、スーパーアプリはそのバックエンド システムを使用してアップデートを確認し、ダウンロードします。スーパーアプリの中には、ミニアプリ自体がアップデート フローに影響を与えることなく、完全にバックグラウンドでアップデートを行うものがあります。他のスーパーアプリでは、ミニアプリ自体をより細かく制御できます。
複雑なプロセスの例として、以下の段落では WeChat のミニアプリの更新メカニズムについて詳しく説明します。WeChat は、次の 2 つのシナリオで、利用可能なアップデートを確認します。
- 最近使用したミニアプリのアップデートは、WeChat が実行されている間、WeChat によって定期的に確認されます。更新が見つかった場合、更新はダウンロードされ、ユーザーがミニアプリをコールド スタートする次回に同期的に適用されます。ミニアプリのコールド スタートは、ユーザーがミニアプリを開いたときにミニアプリが現在実行されていない場合に発生します(WeChat は、ミニアプリがバックグラウンドで 5 分間経過すると強制終了します)。
- WeChat は、ミニアプリのコールド スタート時にも更新を確認します。ユーザーが長い間開いていないミニアプリの場合、更新が同期的に確認され、ダウンロードされます。アップデートのダウンロード中は、ユーザーは待機する必要があります。ダウンロードが完了すると、アップデートが適用され、ミニアプリが開きます。ネットワーク接続の問題などが原因でダウンロードが失敗した場合でも、ミニアプリが開かれます。ユーザーが最近開いたミニアプリの場合、更新はバックグラウンドで非同期にダウンロードされ、ユーザーが次回ミニアプリをコールド スタートしたときに適用されます。
ミニアプリは、UpdateManager
API を使用して以前のアップデートをオプトインできます。次の機能を提供します。
- アップデートの確認が行われると、ミニアプリに通知します。(
onCheckForUpdate
) - アップデートがダウンロードされて利用可能になると、ミニアプリに通知します。(
onUpdateReady
) - 更新をダウンロードできなかったときにミニアプリに通知します。(
onUpdateFailed
) - 利用可能なアップデートをミニアプリが強制的にインストールできるようにします。これにより、アプリが再起動します。
applyUpdate
WeChat のバックエンド システムには、ミニアプリ デベロッパー向けの追加の更新カスタマイズ オプションも用意されています。1 つの方法では、デベロッパーは、特定の最小バージョンのミニアプリがすでにインストールされているユーザーに対して同期アップデートをオプトアウトし、代わりにアップデートを非同期に強制できます。2. デベロッパーは、ミニアプリの最小バージョンを設定することもできます。これにより、最小バージョンより低いバージョンからの非同期アップデートでは、アップデートの適用後にミニアプリが強制的に再読み込みされます。また、アップデートのダウンロードに失敗した場合、古いバージョンのミニアプリを開くこともブロックされます。
謝辞
この記事は、Joe Medley、Kayce Basques、Milica Mihajlija、Alan Kent、Keith Gu が確認しました。