ウェブページをできる限りネイティブアプリっぽく魅せるテクニックまとめ 〜アップルにリジェクトされつづけるなら、ウェブアプリとストアをつくって自前で配信してしまおうという企み〜

f:id:kimizuka:20161211193503p:plain
https://kimizuka.github.io/web-app-store/example/
北斗市公式キャラクター ずーしーほっきー ©2013 北海道北斗市 を使用させていただいております。

ウェブページをできる限りネイティブアプリっぽくみせて配信するために色々研究しました。


もくじ

  1. はじめに
  2. ウェブアプリとは
  3. 今回制作したもの
  4. ネイティブアプリとの比較
  5. ストア以外での配信方法
  6. ホームアイコンの設定方法
  7. フルスクリーンでの表示方法
  8. オフラインでのアクセス
  9. プッシュ通知(断念)
  10. カメラへのアクセス
  11. GPS / 加速度センサ / ジャイロセンサ へのアクセス
  12. ランドスケープでの固定(断念)
  13. 大技(Safariから開かれたかホーム画面からひらかれたかの判定)
  14. 小技(タップした際の黒ずみ除去 / 長押しでメニューを開かない / テキスト選択不可 / スクロール不可)
  15. その他、実装の上で頑張ったところ
  16. まとめ

1. はじめに

このエントリーは Tech KAYAC Advent Calendar 2016 の12日目の記事です。

techblog.kayac.com


こんにちは。カヤックのフロントエンジニア、@ki_230 です。
普段はウェブフロントエンジニアとして勤務しているのですが、趣味でiPhoneアプリをつくったりもしています。

今年も2本アプリをつくっていたのですが、、、


全然審査を通過できない! (T_T) 


そう。全然審査を通過できないまま2016年が終わろうとしているのです。

ちなみに審査を通過できない理由は、「価値が長続きしない」とのこと。

f:id:kimizuka:20161211164605p:plain
https://developer.apple.com/app-store/review/rejections/jp/ より引用


価値が長続きしない! (T_T) 


別にアップルさんを責めたいわけじゃないんです。
なにに価値を感じるかは人それぞれなわけですから。
ただ、私が本職で無い分、凝ったアプリがつくれないんですね。
大体がウェブでも成立するようなアプリになってしまうんです。

しかし、ここで逆転の発想です。

こうなったら、ウェブアプリで実装してしまおう。と。
そして、それを配信する仕組みもつくってしまおう。と。
アップルから逃げるのは恥ではあるのだけど、役に立つであろう。と。

そう決意したところからこのプロジェクトははじまりました。


2. ウェブアプリとは

定義

一般的なウェブアプリとは、ウェブ上で動作するアプリケーションのことですが、
今回はサーバサイドをつかわずに HTML + CSS + JavaScript で動作するアプリケーションのこととします。

配信方法

iOSのSafariにはホーム画面に追加という、ウェブクリップをホーム画面に追加する機能があります。
例えば カヤックサイト をホーム画面に追加すると、、、

f:id:kimizuka:20161211165801g:plain

こんな感じです。
今回はこの機能をつかって、ユーザーにホーム画面においてもらうことを配信と呼ぶことにしましょう。


3. 今回制作したもの

  1. iOSのSafariからアクセスした際はストアっぽい見た目になる
  2. ホーム画面に追加してから開いた際はアプリっぽい見た目になる
  3. ホーム画面に登録して1度開けば、2度目以降はオフラインでも開ける

また、

  1. Androidからアクセスした場合はアプリっぽい見た目になる
  2. PCなどからアクセスした場合はQRコードが表示される

というものを比較的簡単につくれるフレームワーク風のものをつくりました。
2016年なんで、 React とか Gulp とかつかおうかともおもったんですが、
そんなに複雑なものをつくるわけじゃないので、生HTML、生JavaScriptで書きました。(CSSだけはCompassをつかいました)
オフラインでの動作を考えると、余計なライブラリを読み込ませるのは勿体無いですからね。


DEMO


北斗市公式キャラクター ずーしーほっきー ©2013 北海道北斗市 を使用させていただいております。

Safariで開いたときと、ホーム画面から開いたときで表示が全然違うものになっています。

kimizuka.github.io
※ iPhoneでご観覧ください!

f:id:kimizuka:20161211191536p:plain


リポジトリ

github.com



4. ネイティブアプリとの比較

ネイティブアプリ ウェブアプリ
ストア以外での配信
ホームアイコンの設定
フルスクリーンでの表示
オフラインでのアクセス
プッシュ通知 ×
カメラへのアクセス
GPSへのアクセス
加速度センサへのアクセス
ジャイロセンサへのアクセス
マイクへのアクセス ×
ランドスケープでの固定 ×

前提として、あたりまえのことですが、基本的にネイティブアプリの方が高性能です。
プッシュ通知アプリケーションバッジ をつかいたい場合、マイク をつかいたい場合、 横向きで固定 したい場合はネイティブアプリをつくりましょう。
最近はSafariの性能があがってきているので、簡単なカジュアルゲームぐらいだったらウェブアプリでもなんとかなります。
では、ひとつずつ解説していきましょう。

続きを読む

【Unity】 uGUIについて

はじめに

はじめまして。 カヤックのソーシャルゲーム事業部の Unity エンジニアのです。
今回は Unity の uGUI について紹介します。
この記事はカヤック Unity アドベントカレンダー 2016 の 12 日目の記事です。

uGUI について

Unity 4.6 から新しい UI システム uGUI が搭載されるようになって、Unity 5 では uGUI がさらに更新され、とても便利なツールになりました。
昔は NGUI を使ってたかもしれませんが、新しいプロジェクトではオフィシャルな uGUI を使うのは良いでしょう。

全体像

uGUI では以下の構造になっています。

  • Canvas:子にUI要素(画像やボタンとか)を持つ
  • EventSystem:マウス操作、タッチ操作、キーボード操作などから発生するイベント処理を担当する

各 UI コンポーネントの紹介について、Unity - Manual: UI を見ながら、Unity 上で試してみるとすぐにわかると思います。

レンダリング

GUI とはいえ、実装上で注意しないと Batch 数が増え、ゲームが重くなるので、レンダリングのチューニングがとても重要になっています。

テクスチャの設定

Packing Tag

Sprite ごとに Packing Tag が設定でき、同じ文字列に設定された Sprite が自動的に一つのテクスチャにパックされます。
これにより、同じ Packing Tag の画像を連続で描画する時に、GPU の Render State の切り替えをしなくていいので、一回で描画できて、レンダリングが速くなります。

Packing Tag は場合によって慎重に設定することが大事です。
例えば:

  1. LayerA: PackA
  2. LayerB: PackB
  3. LayerC: PackA

の場合に、LayerB が LayerA と LayerC に被るエリアがあったら、描画時に Batch できないため、合計 3 回レンダリングする必要があるのです。
LayerB の Packing Tag を PackA に設定すると、全部 Batch できるので、1 回でレンダリング出来ます。

その他注意すべきこと:

  • Resources.Load 系のメソッドで動的にロードされた Sprite は、事前に Packing Tag を設定しても効かないので、この場合は Sprite Sheet などを使うのをオススメです。
  • フォントを使う文字は別テクスチャになるので、普通の画像と Batch できません。
  • Image の Color の Alpha を 0 に設定しても、レンダリングされて無駄な描画負荷になってしまうので、隠したい場合は Disable にするのがオススメです。
  • Image の Sprite を設定しないなら、デフォルトの空画像が使われます。これのせいで Batch 数が増えるかもしれません。

Generate Mip Maps

この設定は同じ画像の低い解像度のバージョンを自動で生成するという意味です。3D のシーンでは Sprite が遠い場所にあったら自動的に低い解像度の画像を使う場合が多いが、GUI の場合はほとんど使われないです。
この設定をオンにすると、無駄な Sprite パックが生成されるから、使わないときはオフにするのを忘れないようにしましょう。

Sprite Packer

パッケージされた Sprite を確認したり、ポリシーを変えてリパックしたりする便利ツールです。
Unity - Manual: Sprite Packer
使う前にドキュメントをチェックしてみましょう。

画像ファイルが実機のメモリで展開されるときに、サイズが 2 の整数乗になるので、パッケージされた画像も全部 256, 512, 1024 などのサイズになっています。

Auto Layout

オブジェクトをグループで表示したい場合によく使うコンポーネント集。位置、サイズ調整が自動でやってくれるなど、是非活用してみてください。
Unity - Manual: Auto Layout

スクロールビュー

uGUI では簡単にスクロールビューが作れます。Auto Layout と合わせて使うと、ダイナミックな表現もできて、とても楽なのです。
スクロールビューの使い方はドキュメントを見るといいでしょう。
Unity - Manual: Scroll Rect

イベントシステム

EventTrigger

UI エレメントでマウスダウンやクリックなどのイベントをつけたい場合はよくあると思います。 この時は EventSystems のインターフェースを実装するのがいいです。

using UnityEngine;
using UnityEngine.EventSystems;

public class EventTriggerExample : IPointerDownHandler
{
    public void OnPointerDown(PointerEventData data)
    {
        Debug.Log( "OnPointerDown called." );
    }
}

既存のイベントはここに参考しましょう:
Unity - Scripting API: EventTrigger

IEventSystemHandler

時にはカスタムなイベントを作りたいかもしれないですね。この場合は IEventSystemHandler を使いましょう。

using UnityEngine;
using UnityEngine.EventSystems;

public interface ICustomEventHandler : IEventSystemHandler
{
    void OnCustomEvent();
}

public class Example
{
    private static void InvokeOnCustomEvent(ICustomEventHandler target, BaseEventData data)
    {
        target.OnCustomEvent();
    }

    private void Execute(GameObject target)
    {
        ExecuteEvents.Execute<ICustomEventHandler>(target, null, InvokeOnCustomEvent);
    }
}

その他

uGUI はオープンソースになっています。
ハマったり、深く勉強したかったり、拡張したかったりする場合は、ソースを見るのがオススメです。リポジトリはこちら:
Unity-Technologies / UI - Bitbucket