MBaaS徹底入門――Kii Cloudでスマホアプリ開発

第8回 Kii Cloudを用いたチャットアプリケーションの開発 [その4] ―メッセージ送受信機能の実装

この記事を読むのに必要な時間:およそ 9 分

前回は,チャットルームの実装について解説しました。第8回となる今回は,チャットアプリケーションのメイン機能であるメッセージの送受信機能を実装していきます。テキストメッセージのやりとりだけでは少し寂しいので,最近流行りのスタンプを送信できる機能も追加で実装したいと思います。

今回使用したソースコードについては,GitHubで公開しています。こちらもあわせてご覧ください。

メッセージ送受信機能の実装

実装に入る前に,第5回で説明したメッセージ送受信機能について簡単に確認してみましょう。新たにスタンプを送信する機能を追加することになったので,第5回で説明したデータフローにスタンプを保存するchat_stampsバケットが追加されています。

メッセージ送受信時のデータフロー

メッセージ送受信時のデータフロー

  • 新規スタンプのアップロード:ユーザは好きな画像をchat_stampsバケットにアップロードすることでスタンプとして利用できます。アップロードされたスタンプはチャットを利用するすべてのユーザが使用することができます。
  • スタンプ一覧の取得:スタンプを送信する場合は,まず,chat_stampsバケットを検索して利用可能なスタンプの一覧を取得します。その後,1件ずつスタンプの画像をダウンロードして画面に表示します。
  • メッセージの送信:メッセージの送信はchat_roomバケットにKiiObjectを保存することで実現できます。チャットの相手は対象のchat_roomバケットを購読しているはずなので,新しいKiiObjectを保存するだけで,自動的にプッシュ通知が相手に届きます。
  • メッセージの受信:メッセージの受信はプッシュ通知を契機におこないます。プッシュ通知を受信したら,対象のchat_roomバケットを検索しメッセージを取得して画面に表示します。受信したメッセージがスタンプを含んでいる場合は,スタンプの画像をダウンロードします。同じ画像を何回もダウンロードする必要がないように,画像は端末にキャッシュとして保存しておきます。

この4つのフローの実装について,以下で説明していきます。

①新規スタンプのアップロード

スタンプはアプリケーションスコープのchat_stampバケットに保存されるKiiObjectとして実装します。今まで説明してきたKiiObjectと異なる点は,Object Bodyとして画像ファイルを保持するところです。アップロード処理のフローは以下になります。

新規スタンプのアップロードのフロー

新規スタンプのアップロードのフロー

スタンプに関係する処理は基本的にChatStampクラスに実装されています。さっそく実際のコードを見ていきましょう。

public class ChatStamp extends KiiObjectWrapper {
   private File imageFile;
   private String uri;
   public ChatStamp(File imageFile) {
       super(getBucket().object());
       this.imageFile = imageFile;
   }
   public ChatStamp(KiiObject kiiObject) {
       super(kiiObject);
       this.uri = kiiObject.toUri().toString();
   }
   public ChatStamp(ChatMessage message) {
       super(KiiObject.createByUri(Uri.parse(message.getStampUri())));
       this.uri = message.getStampUri();
   }

   public void save() throws Exception {
       this.kiiObject.save();
       if (this.imageFile != null) {
           this.uri = this.kiiObject.toUri().toString();
           KiiUploader uploader = this.kiiObject.uploader(KiiChatApplication.getContext(), this.imageFile);
           uploader.transfer(null);
           // アップロードしたファイルを,KiiObjectのURIに応じた名前にリネームする
           File cacheFile = StampCacheUtils.getCacheFile(this.kiiObject.toUri().toString());
           this.imageFile.renameTo(cacheFile);
       }
   }
   ...
}

ChatStampクラスは大きく2種類のコンストラクタを提供しています。新たにスタンプを追加する場合は,ファイルを指定するコンストラクタを使用します。スタンプをKiiObjectとして保存した後は,そのKiiObjectのURIを指定するコンストラクタを使用します。

ChatStamp#save()メソッドでKiiObjectの保存と,画像ファイルのアップロードを行っています。

まずKiiObject#save() でKiiObjectを保存します。このタイミングでこのスタンプのURIが割り当てられます。次にKiiObject#uploader(Context, File) でKiiUploaderのインスタンスを生成し,KiiUploader#transfer(KiiRTransferProgressCallback)で画像ファイルをアップロードしています。実際にアップロードしているファイルはユーザがギャラリーアプリケーションから選択した画像ファイルを適切なサイズに縮小したファイルになります。

また,今回のケースではアップロードの進捗状況を管理する必要がないのでKiiRTransferProgressCallbackにはnullを指定していますが,サイズの大きいファイルなどをアップロードする場合はKiiRTransferProgressCallbackを使ってユーザに進捗状況を通知したほうがいいでしょう。

最後に,アップロードした画像ファイルをキャッシュに移動しています。こうすることでこのスタンプを再度表示する際にKiiCloudからダウンロードしないですみます。

②スタンプ一覧の取得

スタンプ一覧の取得は,大きく2つの処理に分割されます。

  • “chat_stampsバケット内のすべてのオブジェクトを検索する(画像は含まない)
  • 取得したKiiObject全てに対して画像を取得する

“chat_stampsバケットを検索しただけでは,スタンプの画像(Object Body)は取得できません。表示する必要が生じたタイミングでそれぞれ個別に画像をダウンロードする必要があります。

実際のソースコードは,画像のキャッシュ処理や,ダウンロードのキャンセル処理などを実装しているため,少々複雑になっていますが,ここではKiiCloudとのやりとりの部分に絞って説明します。興味のある方は是非,ソースコードをダウンロードして他の部分も読んでみてください。

まず,ChatStampクラスに実装されているスタンプ一覧を取得する処理を見ていきます。

スタンプ一覧の取得には第6回でも登場したKiiQueryを使用します。今回は,"chat_stamps"バケット内の全てのスタンプを取得して,_createdプロパティの値によりソートします。

これはスタンプの表示順が毎回変わってしまうのを防止するためです。

“_createdはKiiObjectを保存するとKiiCloudが自動的に追加するプロパティでKiiObjectが保存された日時が保存されています。同様に更新日時が保存される"_modified"もあります。

これらのプロパティは一覧を時系列でソートしたい場合にとても役に立ちます。

public static List<ChatStamp> list() {
   List<ChatStamp> stamps = new ArrayList<ChatStamp>();
   try {
       // 作成日時でソートして,クエリ結果の順序を保証する
       KiiQuery query = new KiiQuery();
       query.sortByAsc(FIELD_CREATED);
       List<KiiObject> objects = getBucket().query(query).getResult();
       for (KiiObject object : objects) {
           stamps.add(new ChatStamp(object));
       }
       return stamps;
   } catch (Exception e) {
       Logger.e("Unable to list stamps", e);
       return stamps;
   }
}

つづいて画像をダウンロードする処理を見ていきましょう。アップロード処理のコードと非常に似ていて簡単に理解できるかと思います。

KiiObject#downloader(Context, File) KiiDownloaderのインスタンスを生成しKiiDownloader#transfer(KiiRTransferProgressCallback)で画像ファイルをダウンロードしています。

public Bitmap getImage() {
   try {
       byte[] image = null;
       if (this.imageFile != null) {
           // ファイルを指定してChatStampのインスタンスが生成された場合 (新規スタンプの追加時)
           image = readImageFromLocal(this.imageFile);
       } else if (this.uri != null) {
           // イメージがキャッシュされていれば,キャッシュから読み込む
           File cacheFile = StampCacheUtils.getCacheFile(this.uri);
           if (cacheFile.exists()) {
               image = readImageFromLocal(cacheFile);
           } else {
               // キャッシュに存在しない場合は,KiiCloudからダウンロードする
               Logger.i("downloads stamp image from KiiCloud");
               KiiDownloader downloader = kiiObject.downloader(KiiChatApplication.getContext(), cacheFile);
               downloader.transfer(null);
               image = readImageFromLocal(cacheFile);
           }
       }
       if (image != null) {
           return BitmapFactory.decodeByteArray(image, 0, image.length);
       }
       Logger.w("failed to download stamp");
       return null;
   } catch (Exception e) {
       Logger.e("failed to download stamp", e);
       return null;
   }
}

著者プロフィール

福崎範佳(ふくざきのりよし)

Kii株式会社

http://www.kii.com/

コメント

コメントの記入