Monacaからkintoneに画像をアップロードする方法

[以前の記事](https://qiita.com/coboco/items/8758ad28fa6b77a2cea2)でMonacaとkintoneとの連携方法について解説しました。
今回はkintoneに添付ファイル（画像）をアップロードする方法を紹介します。
添付ファイルの登録は単純なテキストデータの登録とは異なり、クライアント側のロジックに一手間加える必要があります。
ポイントは以下の2点です。

+ Cameraプラグインで取得した画像をBlob形式に変換する
+ 一度kintoneに画像をアップロードしてから、レコードと画像を関連付ける

## サンプルアプリ

### ログイン画面
kintoneのアカウントを入力してログインを実行します。

![Image uploaded from iOS.png](https://qiita-image-store.s3.amazonaws.com/0/152304/8d5de4b9-d0ca-ccfa-93cf-2167de3ea4ab.png)

### 登録画面
「写真を選択」ボタンで端末内の写真を選択した後に、「送信」ボタンでkintoneへの登録を実行します。

![Image uploaded from iOS (1).png](https://qiita-image-store.s3.amazonaws.com/0/152304/85af3697-24a9-aa0d-3a2f-c960ae0cc97e.png)

### 実行結果
kintoneアプリの添付ファイルフィールドに、画像が登録されます。

<img width="437" alt="スクリーンショット 2017-12-14 0.50.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/152304/146ea382-cfc8-b04a-bccb-84c114076f48.png">


## ソースコード
```html:index.html
<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="css/style.css">
  <!-- kintone Utility Libraryの読込 -->
  <script src="js/kintoneUtility.js"></script>

  <script>
    // kintoneのアプリ情報
    let appInfo = {
      id: 1,  // 自分のアプリIDに変更してください
      domain: 'サブドメイン.cybozu.com'  // 自分のサブドメインに変更してください
    };

    // ログイン処理
    function login() {
      let name = document.querySelector('#name').value;
      let pass = document.querySelector('#pass').value;
      
      // ドメイン情報の設定
      kintoneUtility.rest.setDomain(appInfo.domain);
      // 認証情報の設定
      kintoneUtility.rest.setUserAuth(name, pass);
      // 登録画面に遷移
      document.querySelector('#navi').pushPage('entry.html');
    
    }

    // 写真を選択ボタン押下時の処理
    function choosePic() {
      // 写真を読み込み
      navigator.camera.getPicture(onSuccess, onError, { 
        sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
        destinationType: Camera.DestinationType.FILE_URI
      });
      
      // 写真のパスが取得される
      function onSuccess(imageURI) {
        document.querySelector('#photo').src = imageURI;
      }
    }
    
    // 送信ボタン押下時の処理
    function onSendBtnClick() {
      // 写真のパスを取得
      let imageURI = document.querySelector('#photo').src;
      
      // 写真が選択されている場合
      if (imageURI.length > 0) { 
          // URIからFileEntryに変換する
          window.resolveLocalFileSystemURL(imageURI, resolveOnSuccess, onError);
      }
    }
    
    // FileEntry取得完了時の処理
    function resolveOnSuccess(fileEntry) {
      // Fileオブジェクトを取得
      fileEntry.file((file) => { 
        // FileReaderを生成
        let reader = new FileReader();
        // ArrayBuffer形式への変換完了時の処理
        reader.onloadend = uploadPic;
        // ArrayBuffer形式に変換
        reader.readAsArrayBuffer(file);
      }, onError);
    }
    
    // kintoneに画像をアップロード
    function uploadPic(event) {
      // ArrayBufferからBlobに変換する
      let file = new Blob([event.target.result]);
      // まず、kintoneに画像ファイル単体をアップロード
      kintoneUtility.rest.uploadFile({
        fileName: 'sample.jpg',
        blob: file
      })
      .then(function(response) {
        // 画像に割り当てられたファイルキーが返却される
        postToKintoneApp(response.fileKey);
      })
      .catch(onError);
    }
    
    // kintoneアプリにレコード登録
    function postToKintoneApp(key) {
      kintoneUtility.rest.postRecord({
        app: appInfo.id,
        record: {
          "添付ファイル": {
            // 画像のファイルキーを指定して、レコードに関連付ける
            value: [{fileKey: key}]
          }
        }
      })
      .then(function(response) {
        console.log(response);
        alert("登録しました");
      })
      .catch(onError);
    }

    // エラー時の処理
    function onError(error) {
      console.log(error);
    }

  </script>
</head>
<body>
  <ons-navigator id="navi" page="login.html"></ons-navigator>

  <!-- ログイン画面 -->
  <template id="login.html">
    <ons-page>
      <ons-toolbar>
        <div class="center">ログイン</div>
      </ons-toolbar>
  
      <div class="login-form">  
        <ons-input type="text" modifier="large underbar" placeholder="アカウント名" value="" id="name"></ons-input>
        <ons-input type="password" modifier="large underbar" placeholder="パスワード" value="" id="pass"></ons-input>
        <ons-button id="loginButton" modifier="large" onclick="login()">ログイン</ons-button>
      </div>
    </ons-page>
  </template>
  
  <!-- 登録画面 -->
  <template id="entry.html">
    <ons-page>      
      <ons-toolbar>
        <div class="center">写真登録デモ</div>
      </ons-toolbar>
      
      <div class="entry-form">
        <ons-button onclick="choosePic()" modifier="large">写真を選択</ons-button>
        <img id="photo" src="">
  
        <ons-button onclick="onSendBtnClick()" modifier="large">送信</ons-button>
      </div>      
    </ons-page>
  </template>
</body>
</html>
```

## 添付ファイルアップロード処理について
[kintone Utility Library for JavaScript](https://github.com/kintone/kintoneUtility) を使用して画像ファイルをアップロードするには、以下の手順で処理を実行します。

### 画像ファイルのアップロード
```
kintoneUtility.rest.uploadFile({
  fileName: 'ファイル名',
  blob: Blob形式の画像データ
})
```
引数にオブジェクト形式でファイルの情報を指定します。`blob`プロパティには、Blob形式に変換した画像データを指定します。画像データをBlobに変換する処理については[こちらの記事](https://qiita.com/coboco/items/97bdfbd2c9b16b280eae)で解説しています。
このメソッドの戻り値はPromiseです。アップロード成功時には画像ファイルに割り当てられた「ファイルキー」が返されます。
この時点ではまだ、kintoneアプリのレコードには登録されていません。

### kintoneアプリのレコードに画像ファイルを関連付ける
```
kintoneUtility.rest.postRecord({
  app: アプリID,
  record: {
    "フィールドコード": {
      value: [{fileKey: ファイルキー}]
    }
  }
})
```
このメソッドは、kintoneアプリにレコードを登録する命令です。
添付ファイルフィールドへの登録値として、画像の「ファイルキー」を指定することでレコードと画像ファイルの関連付けが行われます。

## おわりに
Monacaとkintoneの連携は比較的容易に行うことができるのですが、画像ファイルを登録しようと思うと一気に面倒になりますね…。
画像アップロード&レコードへの関連付けが1つのメソッドで同時に行えて、Blob以外のデータ形式にも対応されると、もっと楽になるのですが…。
kintone Utility Libraryのバージョンアップに期待しましょう。