ionic3 localの画像をimgタグに表示

はじめに

cordovaでのアプリ開発。webviewでimgタグにローカルの画像のパスを指定するだけと思ってたけど意外にはまったのでメモしておく。

今回やりたかったことは以下
・端末のフォトライブラリから選択した画像をimgタグに表示
・カメラを起動して撮影した画像をimgタグに表示
・ionic3で実装

使用したプラグインは以下
・cordova-plugin-camera : フォトライブラリへのアクセスとカメラの撮影に使用
・cordova-plugin-filepath : 後述するがAndroidでの画像ファイルへの絶対パスを取得するのに使用

方針

やり方調べていたら情報が実装方法が色々出てきたり古かったりと混乱した。「cdvfile://」「cdvphotolibrary://」とか専用のプロトコルみたいなのも色々出てきた。これらを試そうとしたら、ブラウザ側でプロトコルが不明やらContent Security Policy の設定が足りなかったりとエラーとなり結局やり方がわからなかった。ionic2以降ではcordova-plugin-ionic-webviewがデフォルトで組み込まれていてiOSではUIWebViewでなくWKWebViewがブラウザエンジンとなっていたりするらしい。

で、結局上手くいったやり方は
1. ファイルへの絶対パスを取得。取得したパスに「file://」がついてなければ付ける
2. 1.で取得したURLを引数に、Ionic.WebView.convertFileSrcメソッド(cordova-plugin-ionic-webview)でローカルサーバーのURL(http://localhost:8080)に変換
3. 2.で取得したURLをimgタグに設定

実装

html

<button ion-button (click)="openPhoto()">フォトライブラリ</button>
<img [src]="imageUrl" />

<button ion-button (click)="openCamera()">カメラを起動</button>
<img [src]="imageCameraUrl" />

js(typescript)

import { Component } from '@angular/core'
import { Platform } from 'ionic-angular'
import { Camera } from '@ionic-native/camera'
import { FilePath } from '@ionic-native/file-path'
import { PhotoLibrary } from '@ionic-native/photo-library'

declare var Ionic :any
declare var window;

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  public imageUrl = ""
  public imageCameraUrl = ""

  constructor(
    public navCtrl: NavController,
    public platform: Platform,
    public filePath: FilePath,
    public camera: Camera,
    public photoLibrary: PhotoLibrary
  ) {
  }

  // フォトライブラリ
  openPhoto = () => {
    const options = {
      quality: 100,
      sourceType: this.camera.PictureSourceType.PHOTOLIBRARY,
      destinationType: this.camera.DestinationType.FILE_URI,
      mediaType: this.camera.MediaType.PICTURE
    }
    this.camera.getPicture(options).then((url) => {
      if (this.platform.is('ios')) {

        // url => file://path/to/img.jpg

        // imageUrl => http://localhost:8080/path/to/img.jpg
        let imageUrl = Ionic.WebView.convertFileSrc(url)

        this.imageUrl = imageUrl

      } else if (this.platform.is('android')) {
        // url => content://path/to/img.jpg

        this.filePath.resolveNativePath(url)
        .then(filePath => {

          // filePath => file://path/to/img.jpg

          // imageUrl => http://localhost:8080/path/to/img.jpg
          let imageUrl = Ionic.WebView.convertFileSrc(filePath)

          this.imageUrl = imageUrl
        })
      }
    })
  }

  // カメラ
  openCamera = () => {
    const options = {
      quality: 100,
      sourceType: this.camera.PictureSourceType.CAMERA,
      destinationType: this.camera.DestinationType.FILE_URI,
      mediaType: this.camera.MediaType.PICTURE
    }
    this.camera.getPicture(options).then((url) => {

      // url => file://path/to/img.jpg

      // imageUrl => http://localhost:8080/path/to/img.jpg
      let imageUrl = Ionic.WebView.convertFileSrc(url)

      this.imageCameraUrl = imageUrl
    })
  }

方針のところに書いたとおり、「file://」から「http://」に変換してimgタグにセット。うただしAndroidの場合は「content://」で返ってくるパターンもあるので、その場合は cordova-plugins-filepathプラグインのresolveNativePathを使って「file://」の形に変換することで対応できる。

以上です