githubにpushされたのをhookしてec2で自動的にpullする

今回やりたかったことは、githubの特定のリポジトリにpushしたら、それをhookして、ec2のWebサーバーにPostされ、
自動的にpullして特定ディレクトリを更新。
です。
やったことがなかったので、ひじょうに勉強になりました!

ec2環境を整える

こちらの記事通りやればOK。
なかなか用語などに馴染みがなく理解しずらかったのですがこのあたりは慣れですね。

わずか5分!? AWSのEC2でクラウドなウェブサーバーを構築してみた | 株式会社LIG

rbenvを入れる

ec2にrbenvをインストールする方法 – Hive Color
こちらの記事のとおりやればうまくいきました!
以下、メモ程度でやったことを残しておきます。

install_rbenv.sh

groupadd staff
gpasswd -a ec2-user staff
cd /usr/local
git clone git://github.com/sstephenson/rbenv.git rbenv
chgrp -R staff rbenv
chmod -R g+rwxXs rbenv

yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel make bzip2 autoconf automake libtool bison iconv-devel

mkdir /usr/local/rbenv/plugins
cd /usr/local/rbenv/plugins
git clone git://github.com/sstephenson/ruby-build.git
chgrp -R staff ruby-build
chmod -R g+rwxs ruby-build

あとは、インストールするだけ。

sudo sh install_rbenv.sh

すべてのユーザーでrbenv使えるようにしておく

/etc/profile.d/rbenv.sh
# vi /etc/profile.d/rbenv.sh
export RBENV_ROOT=/usr/local/rbenv
export PATH="$RBENV_ROOT/bin:$PATH"
eval "$(rbenv init -)"

一度ログアウトして再度ログインするか、

source /etc/profile.d/rbenv.sh

する。

rbenvでrubyをインストールする

rbenv install 2.1.2
rbenv rehash
rbenv global 2.2.1

これで、

ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]

こうなればOK!

hook用のWebサーバーはSinatraを使ってみる

ググるとSinatraでやっている方が多々いて、Sinatra久々に触ってみよーということでやってみました。
以下の記事のコードをかなり参考にさせていただきました!

githubにPushしたらwebhooksとSinatraを利用してサイトを自動的に更新する – blog.katsuma.tv
Webサイトをgithubで管理してpush時に自動的に同期する方法 – Blog by Sadayuki Furuhashi

app.js

require 'sinatra'
require 'json'

here = File.dirname(__FILE__)
SCRIPT = "sh -x #{here}/update-website.sh"

set :port, 8080

post '/' do
   begin
      push = JSON.parse(params[:payload])
      system(SCRIPT)
      "ok."
   rescue
      "error."
   end
end

get '/' do
  system(SCRIPT)
  "ok."
end

サンプルにもう書かれていて、他の記事にもJSON.parse(params[:payload])でpayloadというのが取れるというのが書かれていたのですが、
どうも今試してみると、取れなかった。

その変わり、githubに

Which events would you like to trigger this webhook?
Just the push event.

というラジオボタンがあったので、postの中身は、

post '/' do
  system(SCRIPT)
  "ok."
end

にしてみた。
確かに、イシュー追加しようが、コメント書こうがpostがこなかったので、これでもいいかな。

Rubyで外部コマンドを実行して結果を受け取る方法あれこれ – Qiita

git clone、git pullするshellスクリプト

#!/bin/sh

tmpdir=/var/www/html/hoge
repo=git@github.com:hoge/hoge.git

if [ -d "$tmpdir" ];then
    cd "$tmpdir"
    if git pull; then
        exit 0
    fi
fi

# /var/www/html/
dirname=`dirname "$tmpdir"`
# hoge
basename=`basename "$tmpdir"`

cd "$dirname"

if git clone "$repo" "$basename"; then
  exit 0
fi

Sinatraを起動する

production環境で実行しないと外からのリクエストを受け付けなくなったようなので、以下のように実行。

ruby app.rb -e production

Sinatraがデフォルトでは外部から繋がらなくなってたよ – Qiita

メモ

■yumでインストールしたファイル一覧
rpm -ql nginx
rpm -qa | grep nginx

■サービス一覧
chkconfig –list
3のところが自動起動するかどうか

■自動起動するようにする
chkconfig nginx on

■サービス自体をすぐに起動する
service nginx status
service nginx start

■pemファイルの権限は600にしないとダメ(Mac側)
chmod 600 cliskkey.pem

■ec2にsshログイン
ssh -i key.pem ec2-user@IPアドレス

■postが空いているか確認
telnet IPアドレス 8080

■指定ポートが使われているか確認
netstat -anp | grep 8080

■/var/www/htmlのownerを変える
chown ec2-user:ec2-user /var/www/html

参考リンク

Webhooks | GitHub API

Amazon Web Services クラウドデザインパターン実装ガイド
大澤 文孝
日経BP社
売り上げランキング: 43,041

Unityで2Dゲーム系アプリを作るときのメモ

iOSで60FPS出す方法

Is it possible to get above 30 FPS on an iOS device? – Unity Answers

Androidだとデフォルトで60FPSが出ているんですが、iOSで試すとFPSが30しかでません。
これだと、アニメーションの速度などに差異が出てしまうので、同じにしたいもんです。

Application.targetFrameRate = 60;

これだけでOK!

UnityアプリをiOSで書きだしてビルドするとdSYMのところですんごい時間かかる

  • XCodeのプロジェクト設定ページからBuild Settingsタブを選択
  • dSYMでBuild Options項目を検索
  • DWARF with dSYM fileからDWARFに変更
  • via: UnityアプリをiOSに書き出す時間をdSYMを無効化して早くする – The jonki

    これで解決!
    1分以上かかっていたビルドが数秒になります。

    ただ、XCode上から設定するので、これ以降はUnityはappendでビルドしないといけないかもです。

    prime31のEtceteraTwoの在処が分からない

    LocalNotificationのスケジューリングをしようとすると、EtceteraプラグインだけではダメでTwoのほうが必要になります。
    AndroidのほうはなぜかEtceteraだけでいけるんですが、iOSは2個必要みたい。

    このtwoプラグインはAssetStoreにありません。
    なので、以下のURLから購入することができます。
    prime[31] – the best Unity native code plugins

    ただ、LocalNotificationをただ通知したいだけなら、iOS・Android含めたコードは、

    #if UNITY_IPHONE
            LocalNotification l = new LocalNotification();
            l.applicationIconBadgeNumber = 1;
            l.fireDate = System.DateTime.Now.AddSeconds(10);
            l.alertBody = "hello world";
            NotificationServices.ScheduleLocalNotification(l);
    #elif UNITY_ANDROID
            EtceteraAndroid.scheduleNotification( 10, "Notiifcation Title", "The subtitle of the notification", "Ticker text gets ticked", "my-other-special-data" );
    #endif
    

    こんな感じでもいいかなーと思います。
    LocalNotificationのためだけにtwoで$65払うのもちょっとね。

    PlayerPrefs

    ちょいと値を保存したいとき用に使える。

    Unity – Scripting API: PlayerPrefs

    複数のシーンをマージしてロードする

    テラシュールウェア [Unity3D]ロードの待ち時間を短くする(その4/Application.LoadLevelAdditive)
    このあたりを読むとApplication.LoadLevelAdditiveはかなりオーバーヘッドがあるようで、あまりシーンの分割をしすぎるのは危険のよう。

    開発する人数が多いとシーンの分割はしたくなるが、ある程度最小限のほうがよさそう。

    今回はUnity3D – Unity3Dで、体感ロード時間を減らす – Qiitaを参考にApplication.LoadLevelAdditiveAsyncを採用してみた。

    ただし、非同期で読み込むので、読み込みが完了したかが分からなかったので、以下のようにあるオブジェクトがFindできたらLoadしたとみなす処理を書いた。

    Application.LoadLevelAdditiveAsync ("Game");
    
    StartCoroutine (ObjectChecker (0.1f, () => {
        Debug.Log ("OnLoad---------------------------------");
    }));
    
    IEnumerator ObjectChecker (float secs, Action callback)
    {
        while (GameObject.Find(ConstantsUI.GAME_CAMERA) == null) {
            yield return new WaitForSeconds (secs);
        }
    
        callback ();
    }
    

    このあたりもっと良い方法がないかなー

    NGUIについて

    2Dのゲームアプリを作るため、NGUIを使ってみました。
    はじめの数日はハマることが多いですが、手に馴染んでくるとこれなしでは2Dアプリは作れないという印象。

    NGUIのレンダリングコントロール

    少しやっかいだったのが、レンダリングの順番をどうコントロールするか。

    UIPanelのRenderQでStartAtにしてここでコントロールした。
    NGUIはどうもRenderQueueが3000番から始まるようで、ここを知っていればレンダリングのコントロールは用意です。

    NGUIのコントロールとUnityの3Dコントロール、たとえばパーティクルとかを一緒に使う場合は、以下のようなコードをパーティクルにつけて、3001とかになるようにすればパーティクルが手前にレンダリングされます。

    ■参考リンク

    Webデザイナーが覚えるUnity その2 NGUIの基礎知識 | GREE Creators Blog
    【Unity】NGUIを使ってボタンを実装する。 | albatrus.com
    ゲームは初心者にやさしく: NGUI 描画順について
    NGUIではないオブジェクトをNGUIの手前に描画する方法 – 太郎Work
    ウダサンコウボウ: [Unity]NGUIのDepth設定
    ウダサンコウボウ: [Unity]NGUIのDepth設定その2(複数Atlas)

    NGUIのアニメーションをプログラムから指定する

    TweenPosition tp = TweenPosition.Begin (gameObject, 0.5f, new Vector3 (0, 0, 0));
    tp.tweenGroup = 0;
    tp.from = new Vector3 (transform.localPosition.x, transform.localPosition.y, transform.localPosition.z);
    tp.method = UITweener.Method.EaseInOut;
    tp.style = UITweener.Style.Once;
    tp.AddOnFinished (new EventDelegate (OnShowOverlayEnd));
    tp.Play (true);
    

    ■参考リンク
    開発メモ 「NGUIのまとめ(スクリプトから動的動作)」 – シヴァのブログ
    NGUI TweenPostion.. – Unity Answers
    NGUI: Next-Gen UI kit: TweenPosition Class Reference
    【Unity】NGUIのTweenを利用してみる | albatrus.com

    NGUIのイベントたち

  • void OnHover (bool isOver) – マウスポインタが重なったときに呼ばれます。タップは×。
  • void OnPress (bool isDown) – マウスによりクリック(押下時と離脱時の2回)が発生したときによばれます。タップも○。
  • void OnClick() — 上と同じですが、離脱時の1回だけ呼ばれるパターン。
  • void OnDoubleClick () — ダブルクリックされたとき。
  • void OnSelect (bool selected) –選択メニューで便利?OnClickと同じだけど、こっちは他のものが選択されるまでは2度目の選択時には呼ばれません。
  • void OnDrag (Vector2 delta) – OnPress(true) と OnPress(false)の間に起きた移動を取得。タップ○。
  • void OnDrop (GameObject drag) – ドロップ時(OnPress(false)のタイミング)にドロップされた(下にある)オブジェクト側で呼ばれる。引数には、ドロップした(上にある)オブジェクトが渡される。
  • void OnTooltip (bool show) – Sent after the mouse hovers over a collider without moving for longer thantooltipDelay, and when the tooltip should be hidden. Not sent on touch-based devices.
  • void OnScroll (float delta) マウスのホイールが動いた時によばれる
  • void OnKey (KeyCode key) キーボードが押されたときによばれる
  • via: NGUIでイベントを取得する | Unity3Dのプラグインによる開発

    こちらのサイトにはほんと助けられました。
    どうゆうイベントがいつ呼ばれるのかまったく分かりませんでした。

    動画をネイティブのプレイヤーでフルスクリーンで再生する

    Handheld.PlayFullScreenMovie ("main_movie.mp4", Color.black, FullScreenMovieControlMode.Full);
    

    たったのこれだけ、ただUnity上で実行するのではなくあくまでもネイティブのプレイヤーを表示するので、
    使いどころとしては、何かチュートリアル的な動画などを再生するときかなー

    Unity – Scripting API: Handheld.PlayFullScreenMovie
    Handheld.PlayFullScreenMovie on Android | Unity Community

    Unity4入門   最新開発環境による簡単3Dゲーム製作
    浅野 祐一 荒川 巧也 森 信虎
    ソフトバンククリエイティブ
    売り上げランキング: 1,332

    UnityでFacebookSDKを使う際の注意点

    デフォルトのAndroidManifestでは横向きで動かない

    FacebookSettingでRegenerate Android ManifestでAndroidManifestをジェネレートできますが、このままでは横向きで動きません。

    <activity android:name="com.facebook.LoginActivity" android:screenOrientation="landscape" android:configChanges="keyboardHidden|orientation" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen">
    

    このようにandroid:screenOrientation=”landscape”とlandscapeとして指定する必要があります。

    Facebook側に登録するHashがkeystoreの状況によって変わってくる

    Facebookと連携するアプリを作る場合、FacebookSettingのDebug Android Key Hashの値をサイト側に登録しますが、
    この値が、アプリをPlayストアに公開できる状態にしているかどうかで変わってしまいます。
    アプリに公開できるというのは、自分でkeystoreを作っているかどうかです。

    UnityのFacebookSettingで見えているHashをいくらサイトに登録しても動きません
    実際に必要なのは、以下のようにコマンドラインから実行したときの値を登録します。

    本番用

    こっちの値をサイトに登録します。

    keytool -exportcert -alias hoge -keystore user.keystore | openssl sha1 -binary | openssl base64

    デバッグ用

    こっちの値はFacebookSettingに表示されている値。
    keystoreを自分で作っていない場合は、ここの値でOK。

    keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

    Android Facebook SDK: Key hash does not match any stored key hashes when uploading google play – Stack Overflow
    android – How to generate Key Hash for facebook SDK In Mac – Stack Overflow
    Unity Android using Facebook SDK, missing Debug Android KeyHash – Stack Overflow
    このあたりハマっている人多いよー

    FB.Login (“email,publish_actions”, LoginCallback)の第一引数には気をつけよう

    Facebookログイン Version2.0(アプリのパーミッション仕様変更)

    ここをちゃんと指定しないと動かなかったです。
    とくに空っぽではダメで、何かしらのパーミッションは自分で指定する必要があります。

    FB.Login ("email,publish_actions", LoginCallback);
    
    Facebook Perfect GuideBook 2014年改訂版
    森嶋 良子 鈴木 麻里子 田口 和裕
    ソーテック社
    売り上げランキング: 11,234

    AndroidのAndroid In App Billingで「アイテムが見つかりませんでした。」の解決方法

    現象について

    UnityでAndroid In App Billing Pluginを使ってアプリ内課金をためす方法
    で、UnityからAndroidの課金のやり方を解説したのですが、ある時から、

    「購入しようとしたアイテムが見つかりませんでした。」

    というエラーが出て、いっこうに課金テストすることができませんでした。

    UnityのPluginが出していたエラーは以下のような感じ。

    You have not queried your inventory yet so the plugin does not have the required information to protect you from coding errors.
    CANNOT fetch sku type due to either inventory not being queried or it returned no valid skus.

    FileBasedKeyValueStore.delete: Attempt to delete ‘lkajsdflkasdlkfjaldkfjaldjflkd’ failed!

    BasicNetwork.performRequest: Unexpected response code 500 for https://android.clients.google.com/fdfe/preparePurchase

    ググると時間がたつと使えるようになるよ。といった記事もあり、待ってみましたがいっこうにダメ!

    さらに調べてみると、公式にアナウンスがあったよう。

    テスト課金、ライセンシング、APK 拡張ファイルのダウンロード 以前はこれらの機能を APK がドラフトの状態でもご利用いただけましたが、最近の変更により、今後は APK が公開されている状態である必要があります。アルファ版もしくはベータ版 APK として公開することでテストが可能で、一般公開する必要はありません。詳細については、Android Developers サイトをご確認ください。

    via
    Android デベロッパー ヘルプ

    つまり、課金の仕組み変わって、ドラフト状態だと課金のテストができないよーというもの。

    Testing In-app Billing | Android Developers
    にもDraft Apps are No Longer Supportedという文章がありました。

    これはハマるよー!わからないよー!

    解決策

    Google Play アルファ版機能を利用してアプリをテストする -でじうぃき
    「購入しようとしたアイテムが見つかりませんでした。」アプリ内課金の実機テストが出来なくなった時の対処法 | 日本VTR実験室

    こちらの記事を読んでもらえれば解決します。

    • Google Playでアルファにapkをアップロードする
    • アルファのテスターのリストを管理をクリックし、テストユーザーを含むGoogleグループを追加する
    • アプリを公開する、キャプチャなどの画像・国・規約に同意などなど
    • 公開したあと(この公開はアルファ公開なので一般にはDLできない)再度テスターのリストを管理をクリックするとURLが書いてあるので、Android端末からアクセスする
    • テストユーザーに含めたGoogleグループに所属しているユーザーならアプリのDLが出来るようになっている
    • アプリがDL出来るようになるまで少し時間が掛かります
    • またすでにUnityから同アプリを入れている場合はアンインストールしておきましょう
    • DLアプリを起動し、課金してみるとやっと念願の課金画面がでてきます

    と、かなり面倒になってしまいました。
    とくに面倒なのが、アプリを修正するたびに課金の確認をする場合はapkのアップロードが必要なところですね。

    この仕様変更は、どうも調べてると5月のどっかでされたようで、確かにその時期からなんかうまくいかないなーと思っていました。

    Hubotを使ってSlack、Hipchatと連携してみる。さらにGitHubへ

    Hubotをインストールする

    はじめてのHubot – Qiita
    こちらのまとめがすごく良かったです。

    Hubotを使うにはnode.jsとredisが必要なのでインストールする。
    ぼくはnodeはnodebrewですでに入れているので、redisだけをbrewから入れる。

    % brew install redis

    redisの起動しておく。

    % redis-server &

    HubotのコマンドはCoffeeScriptで書かれているので、Hubotと一緒にインストールしちゃいます。

    % npm install -g hubot coffee-script

    あとは、Hubotの環境を作ります。

    % hubot –create projectName

    するとprojectNameというディレクトリが作られるので、

    % cd projectName
    % ./bin/hubot

    でHubotのコマンドが打てるようになります。

    Hubot> hubot ping
    Hubot> PONG

    PONGと返ってくればHubotが動いています。
    個人的にはパグ画像を引っ張ってきてくれるコマンドが好きです。(パグかわいい!)

    Hubot> hubot pug me

    これもかわいい!gifの犬画像ヤヴァい!

    Hubot> hubot animate me dog

    HubotをHerokuにデプロイしSlackと連携してみる

    基本的にはここに書かれていることをやるとうまくいく。
    hubot-slack/README.md at master · tinyspeck/hubot-slack

    すでにHubotはインストールしているので、

    % npm install hubot-slack –save

    だけ実行しておく。

    ここからはHerokuにデプロイする方法になります。
    hubot/docs/deploying/heroku.md at master · github/hubot

    Herokuにログインする。

    % heroku login
    Enter your Heroku credentials.
    Email: youremail@example.com
    Password:
    Could not find an existing public key.
    Would you like to generate one? [Yn]
    Generating new SSH public key.
    Uploading ssh public key /Users/you/.ssh/id_rsa.pub

    Herokuにデプロイするためにgitリポジトリを作る。

    % git init
    % git add .
    % git commit -m “Initial commit”

    Herokuアプリケーションを作る。
    redisを使うのでアドオンも追加しておく。

    % heroku create my-company-slackbot
    $ heroku addons:add redistogo:nano

    ここでアプリケーションのURLが作成される。

    HerokuへのデプロイファイルのProcfileを編集する。

    web: bin/hubot –adapter slack

    HubotとSlackをIntegrationさせる。

    Team Integration | Frontend-Team Slack
    こちらより、追加させる。

    % heroku config:add HEROKU_URL=自分のHerokuアプリケーションURL
    % heroku config:add HUBOT_SLACK_TOKEN=HubotとSlackをIntegrationしたときに表示される
    % heroku config:add HUBOT_SLACK_TEAM=HubotとSlackをIntegrationしたときに表示される
    % heroku config:add HUBOT_SLACK_BOTNAME=HubotとSlackをIntegrationしたときに表示される

    忘れちゃいけないのが、Service Configuration先ほど作ったHerokuのアプリケーションURLを入れる。
    これを忘れるといっこうに連携されない。

    最後にHerokuにデプロイしてアプリケーションを起動すればOK!

    % git push heroku master
    % heroku ps:scale web=1

    Slack上で

    slackbot pug me

    のようにコマンドを実行できるようなっているはず。
    @はつけない。

    HubotをHerokuにデプロイしHipchatと連携してみる

    事前にHipchatでGroup Adminよりbot用のアカウントを追加しておく。
    RoleはUserにしておいた。
    Slackと違い、Hipchatは事前にユーザーを追加しておく必要があるみたいだ。

    すでにHubotの環境があるので、そのまま続けてHipchatとも連携してみる。

    hipchat/hubot-hipchat
    基本的にはここのリンクの通りやるとうまくいく。

    icu4cというのをインストールする必要があるが、すでに入っていたのでスキップした。

    % brew install icu4c
    % brew link icu4c

    Hipchatと連携要のnpmをインストールする。

    % npm install –save hubot-hipchat

    Procfileに

    web: bin/hubot –adapter hipchat

    を追加する。
    なので、slackの分を合わせると、

    web: bin/hubot –adapter slack
    web: bin/hubot –adapter hipchat

    こうなる。

    heroku config:add HUBOT_HIPCHAT_TOKEN=HipchatのAPIからtokenを作成する
    heroku config:add HUBOT_HIPCHAT_JID=123_456@chat.hipchat.com
    heroku config:add HUBOT_HIPCHAT_PASSWORD=アカウントのパスワード
    heroku config:add HUBOT_HIPCHAT_ROOMS=123_hoge@@conf.hipchat.com

    HUBOT_HIPCHAT_JIDはbot用に作ったユーザーのJabber IDです。
    はじめ自分のJabber IDにしてて、まったくHubotが動かなくてハマりました。
    XMPP/Jabber account settings

    HUBOT_HIPCHAT_ROOMSが部屋のnameでなく、XMPP JIDなのでお間違えなく。

    最後にデプロイすれば、自動的にHipchatにhubotユーザーが追加される。
    追加されなければ何かが間違っている。

    もしかすると、Roomのパーミッションをopenにしてないと追加されないかもしれない。
    追加されたあとにprivateにすればよい。

    % git push heroku master
    % heroku ps:scale web=1

    ちなみにHubotのコマンドはすごい量が公開されているので、必要ならこちらから取り込もう。
    hubot-scripts/src/scripts at master · github/hubot-scripts

    なかでも、hubot-scripts/src/scripts/zombies.coffee at master · github/hubot-scriptsがきになるが、コードを見ると特定の画像をrandomで出してるだけだったw

    HipchatとGithubを連携させる

    連携メモ – 優々自適
    こちらの記事のとおりだが、一点気をつけるところは、

    GitHub Integration – Help Center

    RoomがXMPP JIDではなく、単純にRoom名なところ。
    ここでもちょいとハマった。

    GitHub実践入門 ~Pull Requestによる開発の変革 (WEB+DB PRESS plus)
    大塚 弘記
    技術評論社
    売り上げランキング: 465

    UnityでImage Effectを使って画面にノイズ入れたり歪ませたりしてみる

    イメージエフェクト リファレンス / Image Effect Reference
    これは楽しい!

    Unity Pro限定ですが、カメラにアタッチするだけでカメラから見えている景色を加工することができます。
    ゲームで敵に遭遇したときのエフェクトとかをこれで作るとかなりそれっぽいかもしれません。

    以下使えるエフェクト一覧。

    via: Unity – Unity Manual

    個人的にはヴォーテックスが楽しい。
    画面を渦上に歪ませられます。

    カメラにVortex Effect Scriptをアタッチした状態で、以下のようにしてみると雰囲気がつかめるかと。

    サンプルプログラム

    using UnityEngine;
    using System.Collections;
    
    public class CameraController : MonoBehaviour
    {
        private VortexEffect ve;
    
        // Use this for initialization
        void Start ()
        {
            ve = gameObject.GetComponent<VortexEffect> ();
            Invoke("VortexAnimation", 5f);
        }
    
        // Update is called once per frame
        void Update ()
        {
    
        }
    
        private void VortexAnimation ()
        {
            iTween.ValueTo (gameObject, iTween.Hash ("from", 0, "to", 1000, "time", 1.5f, "onupdate", "StartGameUpdateHandler", "oncomplete", "CompleteHandler"));
        }
    
        private void StartGameUpdateHandler (float value)
        {
            ve.angle = value;
        }
    
        private void CompleteHandler ()
        {
            iTween.ValueTo (gameObject, iTween.Hash ("from", 1000, "to", 0, "time", 1.5f, "onupdate", "StartGameUpdateHandler", "oncomplete", "VortexAnimation"));
        }
    }
    

    このサンプルでは、初めの5秒はノイズだけでそれ以降はヴォーテックスエフェクトでグルグルします。
    あと、エフェクトをtweenさせたいので、iTween.ValueToを使ってアニメーションさせています。

    サンプルデモ

    Unity Web Player | NoiseSample

    見てわかるUnityゲーム制作超入門 (Game Developer Books)
    掌田 津耶乃
    秀和システム
    売り上げランキング: 19,721

    Unityでgree/unity-webviewを使ってLandscapeでWebViewを表示するときの注意点

    UnityでWebViewを表示しようと思ってググるとgreeのこのプラグインがよく使われているので、試してみました。
    gree/unity-webview · GitHub

    ざっくりとサンプルを書くとこんな感じです。

    using UnityEngine;
    using System.Collections;
    
    public class WebviewSample : MonoBehaviour {
      public string url;
      WebViewObject webViewObject;
    
      // Use this for initialization
      void Start () {
        webViewObject = (new GameObject("WebViewObject")).AddComponent<WebViewObject>();
        webViewObject.Init((msg) => {
          Debug.Log(msg);
        });
        webViewObject.LoadURL("http://google.com/");
        webViewObject.SetMargins(0, 0, 0, 100);
        webViewObject.SetVisibility(true);
      }
    
      // Update is called once per frame
      void Update () {
    
      }
    }
    

    あとは、AndroidManifest.xmlに以下を追加し、変更点を加える。

    インターネットを使えるようにする。

    <uses-permission android:name=”android.permission.INTERNET”/>
    

    これをしないとWebView内のタッチがDOM側に通知されない。

    <meta-data android:name=”unityplayer.ForwardNativeEventsToDalvik” android:value=”true” />
    

    iOSでlandscape時に横幅いっぱいにWebViewが表示されない

    この問題を修正したプルリクがあり、あれちゃんと対応されているなーと思っていたんですが、
    Merge pull request #13 from endavid/fix/iOSLandscape · 3343201 · gree/unity-webview
    どうもunity-webview.unitypackageがこのコードを含んだ状態になっていないようで、これをいくらimportしてもうまくいかなくてハマりました。

    以下のふたつのファイルをimport後に上書きするとこの問題は解消されます。

    1. unity-webview/plugins/WebViewObject.cs at master · gree/unity-webview
    2. unity-webview/plugins/iOS/WebView.mm at master · gree/unity-webview

    参考リンク

    unity-webviewを使ってサイトを表示してみました!! 〜i-tai.net〜
    Unity上でWebViewを表示する | 代打、俺
    Unity で WebView を表示してみた。 | Lonely Mobiler

    Unity4ゲームコーディング 本当にゲームが作れるスクリプトの書き方
    浅野 祐一 荒川 巧也
    SBクリエイティブ
    売り上げランキング: 9,521

    UnityでiOSのPushNotification(APNS)を実装する方法

    UnityでAndroidのPushNotification(GCM)を実装する方法 | ひささん日記のとき同様、Apple Push Notifications (PNS for iOS) – Unity | Games2win Developersこちらのサイトのとおりやってみました。

    iOS版の場合、NotificationServicesを使って自前で書く方法がちょいちょいググると出てくるんですが、この方法はremoteNotificationCountが1以上の場合かどうかで判断していて、ポーリングしないとダメみたいであんまりやりたくありませんでした。
    たとえOnFixedUpdate内でやったとしても常にPushNotificationがあるかどうかのために回すのはあんまりイケていないです。
    このあたりの議論は、Unity 3.5 and Push Notificationsここに載っています。

    その点、prime[31] – Unity plugin documentationはイベントハンドラを登録しておくことができるので、ポーリングする必要がありません。
    今回はこのAssetの使い方がメインになります。

    事前にPushNotification用の.p12(証明書)を作成する

    このあたりはググるとすぐに出てくるので割愛。
    .pemファイルを作る方法が多いのですが、キーチェーンアクセスから.p12ファイルを書き出してそれを使っても動くので、今回は.p12ファイルを使っています。
    (どうゆう環境でPushNotificationするかによるのかもしれません)

    PushNotification用のunitypackageをimportする

    Asset Storeから prime31 Etcetera Plugin などで検索し、購入後にimportしておきます。

    demoのシーンを使ってPushNotificationを試してみる

    demoにシーンがあるので、そちらを表示しておく。

    EtceteraEventListener.cs

    StringBuilderを使うので、以下を追加。

    using System.Text;
    

    アプリ起動時にPushNotification用のdeviceTokenを取得するAPIを実行します。(詳細は別クラスで)
    ここのremoteRegistrationSucceededの中でdeviceTokenが取れるので、PushNotificationを配信するサーバーに登録しましょう。

    private string regURL = null;
    
    void remoteRegistrationSucceeded( string deviceToken )
    {
      Debug.Log( "remoteRegistrationSucceeded with deviceToken: " + deviceToken );
    
      //string apns_env = "production";
      string apns_env = "develop";
    
      StringBuilder urlString = new StringBuilder ();
    
      urlString.AppendFormat ("&appName={0}", WWW.EscapeURL ("app_name")); // provided by G2W
      urlString.AppendFormat ("&app_id={0}", WWW.EscapeURL ("PNS_ID")); // provided by G2W
      urlString.AppendFormat ("&appversion={0}", WWW.EscapeURL ("APP_Version")); // provided by G2W
      urlString.AppendFormat ("&deviceuid={0}", WWW.EscapeURL ("00"));
      urlString.AppendFormat ("&devicetoken={0}", WWW.EscapeURL (deviceToken));
      urlString.AppendFormat ("&devicename={0}", WWW.EscapeURL (SystemInfo.deviceName));
      urlString.AppendFormat ("&devicemodel={0}", WWW.EscapeURL (SystemInfo.deviceModel));
      urlString.AppendFormat ("&deviceversion={0}", WWW.EscapeURL (SystemInfo.graphicsDeviceVersion));
      urlString.AppendFormat ("&apns_env={0}", WWW.EscapeURL (apns_env));
    
      Debug.Log ("http://" + ("hoge.com/" + urlString));
      regURL = urlString.ToString ();
    
      StartCoroutine ("RegDeviceForPush");
    }
    
    IEnumerator RegDeviceForPush ()
    {
      WWW w = new WWW ("http://" + ("hoge.com/" + regURL), UTF8Encoding.UTF8.GetBytes (regURL));
      yield return w;
    
      Debug.Log ("EEEEE: " + w.error);
    }
    

    アプリがフォアグラウンドでPushNotificationを受けた場合。

    void remoteNotificationReceived( IDictionary notification )
    {
      Debug.Log( "remoteNotificationReceived" );
      Prime31.Utils.logObject( notification );
    }
    

    アプリがバックグラウンドでPushNotificationを受け、さらにその通知自体をタップした場合。

    void remoteNotificationReceivedAtLaunch( IDictionary notification )
    {
      Debug.Log( "remoteNotificationReceivedAtLaunch" );
      Prime31.Utils.logObject( notification );
    }
    

    EtceteraGUIManagerTwo.cs

    アプリ起動時にEtceteraBinding.registerForRemoteNotifcationsを呼んで、deviceTokenを登録します。

    if( GUILayout.Button( "Register for Push" ) )
    {
      EtceteraBinding.registerForRemoteNotifcations( P31RemoteNotificationType.Alert | P31RemoteNotificationType.Badge | P31RemoteNotificationType.Sound );
    }
    

    タイミングの話し

    PushNotificationするときに必ずこの話しが出てきちゃう(ぼくだけかな?)んですが、ネイティブの場合は、

    アプリ側でPushが来るパターンは以下の3つ

    1. フォアグラウンドでプッシュ通知を受け取ったとき
    2. アプリのプロセスがバックグラウンドで生きているときにプッシュ通知を受け取り、ユーザーがアクションボタンをタップしたとき
    3. アプリのプロセスがバックグラウンドで生きていないときにプッシュ通知を受け取り、ユーザーがアクションボタンをタップしたとき

    ただ、2の項目は、アプリ内にバッジのようなものを表示する場合は、 ここではやらずapplicationDidBecomeActiveでやるようにしている。
    これの理由は、バックグラウンドにいてアクションボタンではなく、ホーム画面からアプリアイコンをタップされた場合の処理が必要なので、
    あえて、applicationDidBecomeActiveでやっているのです。
    ネイティブの実装例は、PushNotification-iOSandAndroid/iOS/AppDelegate.m at master · hisasann/PushNotification-iOSandAndroidこちらをご覧ください。

    問題はこの2のapplicationDidBecomeActiveでやるような処理をUnityでどうやるかですね。

    ここでNotificationServicesを使ってもできそうなんですが、
    せっかくなので、Etceteraを使ってみましょう。

    if( EtceteraBinding.getBadgeCount() > 0)
    {
      // 何か処理をゴニョゴニョ
    
      // バッジの数値をクリア
      EtceteraBinding.setBadgeCount( -1 );
    }
    

    アプリケーションがOnResumeしたタイミングでこんな感じでPushNotificationが来ていたかどうかを確認できます。

    参考リンク

    prime[31] – Unity plugin documentation
    Unity and IOS push notifications – Google Docs

    詳細! Objective-C iPhoneアプリ開発 入門ノート Xcode5+iOS7対応
    大重 美幸
    ソーテック社
    売り上げランキング: 2,016

    UnityでAndroidのPushNotification(GCM)を実装する方法

    ググってもあんまり有力な記事がなく、AssetStoreを探してみても良さそうなのがなくまだまだUnityでのPushNotificationはこれからなのかなーという印象を受けました。

    過去にネイティブでやったときのコードはgithubにまとめてあるので、そちらをご覧ください。
    PushNotification-iOSandAndroid/Android at master · hisasann/PushNotification-iOSandAndroid

    そんな中、試してみようかと感じた記事がこちら。
    Android PNS for Unity Games | Games2win Developers
    iOS版の記事もあり、そちらはPrime31のAssetを使っていて、良さそう!と思いました。

    Asset Store – Android Etcetera PluginこれのiOS版にはPushNotificationのコードが入っていますが、Android版にはない様子。
    でも↑の記事の中でつかつているunitypackageの中に少しPrime31のコードもあったので、そちらを使うで十分そう。

    事前にSender Id、PushNotification用のIdを作成する

    よくやる作業なので、ここでの説明は割愛。

    この作業はGoogle Developers Consoleで行います。
    ProductIdというのができていたのですが、そちらではPushNotificationがうまく動かず、Project Numberを使うといけました。

    PushNotification用のunitypackageをimportする

    GoogleCloudMessaging-Modified.unitypackage – Google Drive
    こちらからDLし、Unityにインポートしておきます。

    AndroidManifest.xmlを作成する

    ↑のunitypackageを入れると、prime[31]のエディター拡張がインストールされるので、それを使うのが便利です。
    メニューからprime[31] → Generate AndroidManifest.xml Fileこれを実行すると、

    Assets/Plugins/Android

    の下に、AndroidManifest.xmlファイルが作成されます。
    すでにある場合はマージしてくれるようです。

    一応貼っておくとこんな感じ。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.unity3d.player"
        android:installLocation="preferExternal"
        android:theme="@android:style/Theme.NoTitleBar"
        android:versionCode="1"
        android:versionName="1.0">
        <supports-screens
            android:smallScreens="true"
            android:normalScreens="true"
            android:largeScreens="true"
            android:xlargeScreens="true"
            android:anyDensity="true"/>
    
        <application
        android:icon="@drawable/app_icon"
            android:label="@string/app_name"
            android:debuggable="true">
            <activity android:name="com.prime31.UnityPlayerNativeActivity" android:screenOrientation="portrait"
                      android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
                <meta-data android:name="unityplayer.ForwardNativeEventsToDalvik" android:value="true" />
            </activity>
    
            <receiver
                android:name="com.prime31.GCMBroadcastReceiver"
                android:permission="com.google.android.c2dm.permission.SEND">
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                    <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
                    <category android:name="PACKAGE_NAME"/>
                </intent-filter>
            </receiver>
    
        <meta-data android:name="com.prime31.GoogleCloudMessagingPlugin" android:value="UnityPlayerActivityProxy"/>
      </application>
    
      <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
      <uses-permission android:name="android.permission.INTERNET"/>
      <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
      <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
      <permission android:name="PACKAGE_NAME.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
      <uses-permission android:name="PACKAGE_NAME.permission.C2D_MESSAGE"/>
    
    </manifest>
    

    重要な箇所は、

    <receiver
        android:name="com.prime31.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
            <category android:name="PACKAGE_NAME"/>
        </intent-filter>
    </receiver>
    

      <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
      <uses-permission android:name="android.permission.INTERNET"/>
      <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
      <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
      <permission android:name="PACKAGE_NAME.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
      <uses-permission android:name="PACKAGE_NAME.permission.C2D_MESSAGE"/>
    

    ここ。

    PACKAGE_NAMEというのが3箇所あります。
    ここを自分のUnityProjectのBundleIdと同じにします。

    はじめ、1個目のPACKAGE_NAMEしか見えていなく、ここだけ直してビルドしていたらいっこうに通らなくてハマりました。
    そんときのエラーはこちら。
    Android SDK Manifest file error: INSTALL_PARSE_FAILED_MANIFEST_MALFORMED – Stack Overflow

    demoのシーンを使ってPushNotificationを試してみる

    demoにシーンがあるので、そちらを表示しておく。
    EventListenerとuiというGameObjectがあるので、そのソースを表示する。

    GoogleCloudMessagingEventListener.cs

    大事なメンバはnotificationReceivedEventメソッドとregistrationSucceededEventメソッドです。
    元記事のサンプルをもとに書くとこんな感じです。

    using UnityEngine;
    using System;
    using System.Text;
    using System.Collections;
    using System.Collections.Generic;
    
    public class GoogleCloudMessagingEventListener : MonoBehaviour
    {
    #if UNITY_ANDROID
      private string regURL;
      private const string host = "test.com/add/";
    
      //PNS ID provided by the publishing team
      private const string pnsID = "7";
    
      //PNS Environment = should be 'production' in the release build
      private const string pnsEnvironment = "sandbox";
    
      //APP version
      private const string pnsAppVersion = "1.0";
    
      void OnEnable()
      {
        // Listen to all events for illustration purposes
        GoogleCloudMessagingManager.notificationReceivedEvent += notificationReceivedEvent;
        GoogleCloudMessagingManager.registrationSucceededEvent += registrationSucceededEvent;
        GoogleCloudMessagingManager.unregistrationFailedEvent += unregistrationFailedEvent;
        GoogleCloudMessagingManager.registrationFailedEvent += registrationFailedEvent;
        GoogleCloudMessagingManager.unregistrationSucceededEvent += unregistrationSucceededEvent;
      }
    
    
      void OnDisable()
      {
        // Remove all event handlers
        GoogleCloudMessagingManager.notificationReceivedEvent -= notificationReceivedEvent;
        GoogleCloudMessagingManager.registrationSucceededEvent -= registrationSucceededEvent;
        GoogleCloudMessagingManager.unregistrationFailedEvent -= unregistrationFailedEvent;
        GoogleCloudMessagingManager.registrationFailedEvent -= registrationFailedEvent;
        GoogleCloudMessagingManager.unregistrationSucceededEvent -= unregistrationSucceededEvent;
      }
    
    
    
      void notificationReceivedEvent( Dictionary<string,object> jsonDict )
      {
        Debug.Log( "notificationReceivedEvent" );
        Prime31.Utils.logObject( jsonDict );
    
        int badgeNum = int.Parse(jsonDict["badge"].ToString());
        string openURL = jsonDict["open_url"].ToString();
        if(!string.IsNullOrEmpty(openURL))
        {
          Application.OpenURL(openURL);
        }
        GoogleCloudMessaging.setBadge(badgeNum);
        GoogleCloudMessaging.cancelAll();
        showBadge();
      }
    
    
      void registrationSucceededEvent( string registrationId )
      {
        Debug.Log( "registrationSucceededEvent: " + registrationId );
    
        StringBuilder urlString = new StringBuilder ();
        urlString.AppendFormat('?registration_id={0}',WWW.EscapeURL(registrationId));
        urlString.AppendFormat('?app_id={0}',WWW.EscapeURL(pnsID));
        urlString.AppendFormat('?app_version={0}',WWW.EscapeURL(pnsAppVersion));
        urlString.AppendFormat('?apns_env={0}',WWW.EscapeURL(pnsEnvironment));
    
        regURL = urlString.ToString ();
        Debug.Log("regURL: " + regURL);
    
        StartCoroutine ("RegDeviceForPush");
      }
    
    
      void unregistrationSucceededEvent()
      {
        Debug.Log( "UnregistrationSucceededEvent" );
      }
    
      IEnumerator RegDeviceForPush ()
      {
        WWW w = new WWW ("http://" + (host + regURL), UTF8Encoding.UTF8.GetBytes (regURL));
        yield return w;
      }
    
    #endif
    }
    

    GoogleCloudMessagingUI.cs

    重要な箇所は、

    GoogleCloudMessaging.register( "1234567890" );  // sender id
    

    string pushIOApiKey = "lkajdsflkajsdflkajsdflkjadsflkj";  // push key
    

    です。

    using UnityEngine;
    using System;
    using System.Net;
    using System.Collections;
    using System.Collections.Generic;
    using System.Security.Cryptography.X509Certificates;
    using System.Net.Security;
    using Prime31;
    using System.Text;
    using System.Security.Cryptography;
    
    
    public class GoogleCloudMessagingUI : Prime31.MonoBehaviourGUI
    {
    #if UNITY_ANDROID
      private string _registrationId;
    
      void Start()
      {
        // listen for successful registration so we can save off the registrationId in case we want to use it for Push.io registration.
        GoogleCloudMessagingManager.registrationSucceededEvent += regId =>
        {
          Debug.Log("regId: " + regId);
          _registrationId = regId;
        };
      }
    
    
      void OnGUI()
      {
        beginColumn();
    
        if( GUILayout.Button( "Check for Notifications" ) )
        {
          GoogleCloudMessaging.checkForNotifications();
        }
    
    
        if( GUILayout.Button( "Register" ) )
        {
          // replace this with your sender ID!!!
          GoogleCloudMessaging.register( "1234567890" );
        }
    
    
        if( GUILayout.Button( "Unregister" ) )
        {
          GoogleCloudMessaging.unRegister();
        }
    
    
        if( GUILayout.Button( "Cancel All Pending Notifications" ) )
        {
          GoogleCloudMessaging.cancelAll();
        }
    
    
        endColumn( false );
      }
    #endif
    }
    

    アプリを起動して、Registerボタンを押すと、以下のようにLogCatに出力されます。

    04-30 15:02:50.225: I/GCM(9377): GCM config loaded
    04-30 15:02:50.346: I/Prime31-GCMReceiver(17557): recieved broadcast. message type from bundle is null
    04-30 15:02:50.346: I/Prime31-GCMReceiver(17557): received a null message type so we arent interested. aborting
    04-30 15:02:50.406: I/Unity(17557): registrationSucceededEvent: lkajsdflkjasdflkjadsf;lkjadslfkjasd;lfkjalkjasdfl;kjasdf;lkjasdf;lkjasdf
    04-30 15:02:50.406: I/Unity(17557):
    04-30 15:02:50.406: I/Unity(17557): (Filename: ./artifacts/AndroidManagedGenerated/UnityEngineDebug.cpp Line: 53)
    04-30 15:02:50.406: I/Unity(17557): regId: lkajsdflkjasdflkjadsf;lkjadslfkjasd;lfkjalkjasdfl;kjasdf;lkjasdf;lkjasdf
    04-30 15:02:50.406: I/Unity(17557):
    04-30 15:02:50.406: I/Unity(17557): (Filename: ./artifacts/AndroidManagedGenerated/UnityEngineDebug.cpp Line: 53)

    ここのregistrationSucceededEventの中でregisterIdが取れるので、PushNotificationを配信するサーバーに登録しましょう。

    割りと書くコードも少なく、すっきり書けるのでこの方法が僕の中でいまのところ安定しています。
    これからいいAssetとかが見つかれば、そちらの記事をまた書こうかと思います。

    追記:

    タイミングの話し

    UnityでiOSのPushNotification(APNS)を実装する方法 | ひささん日記こちらにも書いたのですが、PushNotificationを受け取るタイミングでひとつ試してなかったのがありました。
    それが、アプリがバックグラウンドにいるときにPushNotificationを受け取って、その後にホーム画面のアプリアイコンをタップした場合にPushNotificationが来ていたかどうかを確認する方法です。
    長いですね。

    結論から言うと、おそらくこの場合のPushNotificationの確認はできません。
    調べたことを順に書いておきます。

    prime[31] – Unity plugin documentationここを見てみると、checkForNotificationsというメソッドがあることに気が付きました。
    書いてあるコメントにもなんだかそれっぽいことが書かれていたので、ここを解析していきました。

    googlecloudmessagingplugin.jarの中にあるclassファイルを全部解凍してみて、見てみると、
    GCMBroadcastReceiverというクラスがありました。
    この中で、

    private void sendNotification(Context context, Bundle bundle, String jsonPayload)
    {
        String launchClassName = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName()).getComponent().getClassName();
        ComponentName comp = new ComponentName(context.getPackageName(), launchClassName);
        Intent notificationIntent = (new Intent()).setComponent(comp);
        notificationIntent.putExtra("notificationData", jsonPayload);
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0x10000000);
        NotificationManager noteManager = (NotificationManager)context.getSystemService("notification");
        android.support.v4.app.NotificationCompat.Builder noteBuilder = new android.support.v4.app.NotificationCompat.Builder(context);
        noteBuilder.setContentIntent(pendingIntent);
        noteBuilder.setAutoCancel(true);
        noteBuilder.setSmallIcon(context.getApplicationInfo().icon);
        noteBuilder.setContentTitle(context.getApplicationInfo().loadLabel(context.getPackageManager()));
        if(bundle.containsKey("message"))
            noteBuilder.setContentText(bundle.getString("message"));
        else
            noteBuilder.setContentText("");
        String tickerText = "Push Notification Received (default tickerText)";
        noteBuilder.setDefaults(1);
        if(bundle.containsKey("message"))
            tickerText = bundle.getString("message");
        noteBuilder.setTicker(tickerText);
        noteBuilder.setWhen(System.currentTimeMillis());
        noteManager.notify(101, noteBuilder.build());
        Log.i("Prime31-GCMReceiver", "notification posted");
    }
    

    ここが、PushNotificationを受けたときに、メッセージを表示している箇所です。
    notificationIntent.putExtraで必要な情報をIntent経由で渡すんだろうなーという感じです。

    そして、GoogleCloudMessagingPluginクラスの中に、該当のクラスがあるので、ここで取得しているんだろうなーという印象。

    public void checkForNotifications()
    {
        Bundle intentExtras = _lastIntent == null ? getActivity().getIntent().getExtras() : _lastIntent.getExtras();
        if(intentExtras != null && intentExtras.containsKey("notificationData"))
            receivedNotification(intentExtras.getString("notificationData"));
    }
    

    とくに何かバグがありそうな気配もないですし、以前は有料?としてAssetStoreで売られていたAssetなので、そんな不備がある可能性は低い。

    そこでprime31のgithubに書かれている、送る側のコードに問題があるんじゃないかと思い、自分のコードは使わず、Simple PHP script showing how to send an Android push notification. Be sure to replace the API_ACCESS_KEY with a proper one from the Google API’s Console page. To use the script, just call scriptName.php?id=THE_DEVICE_REGISTRATION_IDこのコードを使いました。

    それでもやはりバックグラウンドで受けて、フォアグラウンドになったあとにcheckForNotificationsしてもうんともすんとも言わず。

    そのときのログに出ていたこのCANCELLEDが問題なのかなーとググってみても解決策はなし。

    05-02 20:56:00.291: W/GCM/DMM(9377): broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=hoge.hoge (has extras) }

    そこで再度、sendNotificationメソッドの中を見ていたら、PendingIntentというのを使っているのに気がついた。

    あ!
    あああ!

    android初心者プログラミング: PendingIntentによると。

    例えば、Notificationに使う場合は、
    通知バーをタップしたタイミングでIntentが発行されるという感じのようです。

    via: android初心者プログラミング: PendingIntent

    PushNotificationを受けて、通知バーよりタップされた場合にPendingIntent経由でextraDataが登録され、そのあとにcheckForNotificationsを実行するとPushNotificationで来た情報が取得できます。
    なんという限定的!

    これを回避するために、Broadcastする方法がありますが、このプラグインでは採用されていません。

    Intent intent = new Intent(ConstantsUtil.DISPLAY_MESSAGE_ACTION);
    intent.putExtra(ConstantsUtil.GCM_EXTRA_BADGE, badge);
    context.sendBroadcast(intent);
    

    解決策としては、アプリ起動時に毎回PushNotificationがあったかどうかを確認するAPIを呼ぶとかですかねー
    まだどうするのが最適解か考え中です。

    難しい、、、

    Androidの絵本 スマートフォンアプリ開発を始める9つの扉
    株式会社アンク
    翔泳社
    売り上げランキング: 100,308

    UnityでiOS StoreKit In App Purchase Pluginを使ってアプリ内課金をためす方法

    UnityでAndroid In App Billing Pluginを使ってアプリ内課金をためす方法 | ひささん日記でAndroid版を書いています。

    引き続き、prime31Asset Store – iOS StoreKit In App Purchase Pluginのプラグインを使って、iOSの課金のテストをしていきます。

    iOSで課金のテストをするには、iTunesConnectにてアプリを作成し口座登録をし課金アイテムを作成する必要があります。
    このときに、iOS Developer Programでやる必要がありEnterpriseではiTunesConnectにログインができません。

    以下、書くまでもない内容は項目だけ書いています。

    iOS Developer Programに登録する

    Certificates、AppID、Devices登録をしてProvisioning Profilesを事前に登録する

    iTunesConnectにアプリを登録

    Androidでは、実際に仮のapkを登録する必要がありましたが、ここでは必要ではないようで、
    単にアプリを作ればOKです。
    (申請するときと同じ項目いれないといけないのですんごくめんどうですが、、、)

    こちらのまとめでいけた!
    iTunesConnect アプリの登録方法 – 散歩しながら 〜〜アプリ開発〜〜

    口座情報を登録する

    結構面倒なんですが、これをやらないとアイテム作成のところで課金アイテムの登録ができませんでした。

    こちらのまとめでいけた!
    iTunesConnect 銀行口座の登録 – 散歩しながら 〜〜アプリ開発〜〜

    テストユーザーを登録する

    課金するときに使うテストユーザーを作成します。
    AppleIDに紐付いていないメアドでも大丈夫でした。

    こちらのまとめでいけた!
    iTunesConnect テストユーザーの作成 – 散歩しながら 〜〜アプリ開発〜〜

    課金用のアイテムを作成する

    iTunesConnectのアプリページの右側にManage In-App Purchasesボタンがあるのでクリックする。
    左上にあるCreate Newボタンをクリックする。
    講座情報の設定が済んでいれば、ここにいろんなアイテムの種類が並んでいると思います。

    それぞれの違いは以下のとおり。

    Consumable

        消費型

      Non-Consumable

         非消費型

      Auto-Renewable Subscriptions

        自動更新購読

      Free Subscription

        無料購読

      Non-Renewing Subscription

         非更新購読

    via: iTunesConnect アプリ内課金 プロダクト作成 手順 – 散歩しながら 〜〜アプリ開発〜〜

    今回は魔法石的なアイテムを作るので、Consumableを選択します。
    アイテムを作成するときにProduct IDはのちのち使うので、覚えておきましょう。

    via iTunesConnect アプリ内課金 プロダクト作成 手順 – 散歩しながら 〜〜アプリ開発〜〜

    UnityでiOS StoreKit In App Purchase Pluginを使ってみる

    StoreKitEventListener.cs

    そもそもHierarchyに追加したgameObjectが破棄されることがあるのか調査できていないのですが、これを追加。

    void Start ()
    {
        // このオブジェクトが破棄されないようにする
        DontDestroyOnLoad (gameObject);
    }
    

    StoreKitGUIManager.cs

    まずはStoreKitBinding.canMakePayments()でアプリ内の購入制限(子供に触らせる方とか)が掛かっているか確認する。
    (掛かっている場合の挙動はいろんなアプリを見て、促す仕組みが必要なのか要調査)

    if( GUILayout.Button( "Request Product Data" ) )
    {
      // array of product ID's from iTunesConnect. MUST match exactly what you have there!
      var productIdentifiers = new string[] { "magic_stone" };
      StoreKitBinding.requestProductData( productIdentifiers );
    }
    

    ここのstring配列にアイテムのProduct Idを入れる。

    購入が完了すると、StoreKitEventListener.purchaseSuccessful()が呼ばれるのでレシート情報をここで取得しAppサーバーに投げるなど。
    Androidの場合は、購入後に消費しないと何度も同じアイテムが買えなかったですが、iOSのほうは消費型アイテムなので、
    その処理は必要なさそうですね。

    今回もこちらのブログにすごく助けられました。
    [Unity][iOS] prime31 iOS StoreKit Pluginを使用したアプリ内課金の実装 : West Hill 開発メモ

    詳細! Objective-C iPhoneアプリ開発 入門ノート Xcode5+iOS7対応
    大重 美幸
    ソーテック社
    売り上げランキング: 752