A-FrameをAPKに内包してローカルストレージの動画ファイルを再生する

360°動画プレイヤーを手軽に作りたかったので、A-Frameで端末の外部ストレージ(`/sdcard/`)内にある動画を再生するということを試してみました。Android標準のWebViewを使うとパフォーマンスがひどく、まともに見れたもんではありませんでしたが、[Crosswalk](https://crosswalk-project.org/)を使用することでネイティブアプリと遜色ない（というと言い過ぎかな？）くらいパフォーマンスの改善ができました。

## Crosswalkの導入

Crosswalkを導入するためには、まずプロジェクトのルートにある*build.gradle*を編集してリポジトリを追加します。

```groovy:build.gradle
allprojects {
    repositories {
        google()
        jcenter()

        // ↓これを追加
        maven {
            url 'https://download.01.org/crosswalk/releases/crosswalk/android/maven2'
        }
    }
}
```

そして、アプリモジュールの*build.gradle*を編集してライブラリを追加します。

```groovy:app/build.gradle
dependencies {
    implementation 'org.xwalk:xwalk_core_library:23.53.589.4' // これを追加
}
```

※Android Studio 3.0以前は`implementation`ではなく`compile`を使用します。

## サンプルアプリ

それではA-Frameで動画再生サンプルアプリを作ってみましょう。`app/src/main/assets`フォルダを作成して、中にindex.htmlファイルを入れます。このファイルは以下のようになっています。

```html:assets/www/index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WebVR Video Player</title>
  <script src="aframe.js"></script>
</head>

<body>
  <a-scene vr-mode-ui="enabled: false">
    <a-videosphere src="/sdcard/video.mp4" rotation="0 -90 0"></a-videosphere>
  </a-scene>
</body>

</html>
```

それではこのHTMLをActivityに組み込みましょう。Android Studio 3.0からデフォルトで使えるようになったKotlinと[Kotlin Android Extensions](https://kotlinlang.org/docs/tutorials/android-plugin.html)を使ってちょっとだけ簡略化しています。

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

// Android標準のWebViewを使う場合はこの3行が必要
//        webView.settings.javaScriptEnabled = true
//        webView.settings.allowUniversalAccessFromFileURLs = true
//        webView.settings.mediaPlaybackRequiresUserGesture = false

        webView.loadUrl("file:///android_asset/www/index.html")
    }
}
```

UIのリソース(layout/activity_main.xml)はこちらです。わざわざXMLにわけずに直接`onCreate`のコード内で`XWalkView`をインスタンス化しても良いです。

```xml:R.layout.activity_main
<?xml version="1.0" encoding="utf-8"?>
<org.xwalk.core.XWalkView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/webView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```

動画のファイルは外部ストレージの直下`/sdcard/video.mp4`に配置してください。

最後に、外部ストレージにアクセスするためのパーミッションを付けます。

```xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
```

また、今回はランタイムパーミッションの実装を省略しているため、Android 6.0以上で動かす場合はtargetSdkVersionを22以下にしておきます。

```groovy
android {
    defaultConfig {
        applicationId "..."
        minSdkVersion 21
        targetSdkVersion 21 // これが23以上だと
        // ... 以下略
}
```

## 実行例

こんな感じで動画が再生されるはずです！端末を動かせばぐりぐり回れます！

![device-2017-10-31-220733.png](https://qiita-image-store.s3.amazonaws.com/0/56668/33694511-6553-d4c1-f333-12bc5a412077.png)


## Android標準のWebViewを使う場合

ちなみに今後Android標準のWebViewのパフォーマンスが改善されてWebViewで問題なく実装できるようになったときのために、WebViewで実装するときの注意を書いておきます。

* Android標準のWebViewはJavaScriptを実行できないようになっています。WebViewでJavaScriptを実行するには、`WebView.getSettings().setJavaScriptEnabled(true)`を呼び出す
* JavaScriptから外部ストレージに保存している画像や動画にアクセスするために、`WebView.getSettings().setAllowUniversalAccessFromFileURLs(true)`を呼び出す
* モバイル端末で動画を再生するためには**ユーザーのアクション起因のイベントで再生をトリガーしなければいけない**という制約を回避するために、`WebView.getSettings().setMediaPlaybackRequiresUserGesture(false)`を呼び出す

これらの設定を行うことでAndroid標準のWebViewでA-Frameの動画再生サンプルを動かせるようになります。