2013年2月1日金曜日

ボクシングの採点アプリをAppStoreに申請しました。

Android版で先にリリースしていたボクシングの採点アプリをiOSに移植して、AppStoreに申請しました。
これが初iOSアプリです。
無事一発で審査に通るでしょうかね。

しかし、Androidに比べるとStoreにアップロードするまでが格段にめんどくさい!

これが2月1日の出来事。
すぐに「Waiting For Review」になったが、これが次に「In Review」になるらしい。
いつになることやら。

2013年1月25日金曜日

PhoneGapでAdMobを使う(Android版)

PhoneGapでアプリを作って広告収入でお小遣いが入ればいいな、ということで、そのやり方の紹介です。

PhoneGapでアプリを作るときに使う技術って、基本的にはHTML+JavaScript+CSSなので、ワンソースでiOSアプリもAndroidアプリも作れて、めっちゃ簡単。

でも、広告掲載みたいな外部SDKを使うとなるとワンソースじゃ無理なので、OSごとの実装が必要になります。

で、PhoneGapで作ったiOSアプリにAdMobを載っける方法はどなたかがまとめておられます。
http://webdelog.info/2012/09/iphone/cordova-phonegap-ios-admob/

それのAndroid版が日本語で見つからなかったのでここでまとめておきます。
といっても、
https://github.com/phonegap/phonegap/wiki/In-App-Advertisements
に載ってるの抜粋&翻訳です。

SDKのダウンロードとかパブリッシャーIDの発行とかは省略します。

まず、AndroidManifest.xmlのandroid:targetSdkVersionの値が"13"以上になっていることを確認して、applicationタグで囲まれた部分に、
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:name="com.google.ads.AdActivity"></activity>
を追加。

で、Javaの方にある○○Activity(だいたい、アプリケーション名+Activityっていう名前)に、
public class ○○Activity extends DroidGap {
    private Handler mHandler = new Handler();
    private AdView adView;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        super.loadUrl("file:///android_asset/www/index.html");
        mHandler.postDelayed(new Runnable() {
            public void run() {
                doAdMob();
            }
        }, 5000);
    }
    private void doAdMob() {
        adView = new AdView(this, AdSize.BANNER, "パブリッシャーID");
        LinearLayout layout = super.root;
        layout.addView(adView);
        layout.setHorizontalGravity(android.view.Gravity.CENTER_HORIZONTAL);
        AdRequest request = new AdRequest();
        adView.loadAd(request);
    }
}
を追加。

でもこれはLocalStorageを使う場合の実装。
広告を遅らせて表示することでLocalStorageの情報が消えないらしい。
LocalStorageを使ってない場合の実装は、参照元のページを見てください。

2013年1月24日木曜日

AndroidではAdmobメディエーションでi-mobileが使えない件 → 使えるようになりました(2013/01/24)

Admobメディエーションで広告ネットワークの追加ボタンを押したら使えるアドネットワークの一覧が表示されて、i-mobileもそこに名前が出てくる。

選んだら、設定するIDが3つあるので同じ名前の別物ってわけでもなさそう。

でも、設定してSDK入れて準備できたとおもいきや、ビルドするとAdapterクラスが見つからないというエラーが。
なるほど、アダプターを忘れてたのね、とAdMobのサードパーティのSDKやAdapterがダウンロードできるページに行っても、i-mobileが見つからない。

なので、問い合わせました。
すげー早いレスポンスで感動したんですが、回答にはがっくり。
Androidは未対応です、と。

というわけで、同じような現象が起こったらあきらめろ、という結論でお願いします。

【追記】
と書いた数時間後に、使えるようになりました。
記事を参照してください。
すみません。

[PhoneGap2.3.0]ボクシングの採点アプリ、できました。

とりあえずPhoneGapでアプリを作ってみようと思い、自分でもニーズはなかったのですが、たまたまテレビでボクシングをやってたので、それに影響されてラウンドごとに採点して記録するアプリを作りました。

昔、よく採点してたよなぁ。山本に影響されて。

それはともかく、ディープなボクシング好きなら間違いなく誰もがやっているであろう、テレビや会場で試合観戦しながらの採点。
でも、こんなにスマホを持ってる人が増えてるのにわざわざチラシの裏に書いてる。
しかも調べてみたらまともな採点アプリがない。(「ニーズがないからや」とか言わない。)

というわけで、PhoneGapの勉強がてら作りました。

興味があったらダウンロードして使ってください。

「採点しようぜ」
-Android版
https://play.google.com/store/apps/details?id=com.kyosuke25.socialboxing
-iPhone版
開発中

[PhoneGap2.3.0]navigator.notification.confirm は要注意!

PhoneGapで、navigator.notification.confirmを使ってダイアログを表示させ、OKを押したら画面遷移、Cancelを押したらその画面のままという実装をするときの注意点です。
JavaScriptにあるconfirmメソッドと同じ挙動だと思って使うとバグになりますよ、っていう話です。

■confirm()を使う場合

-JavaScript
$('#okButton').click(function(){
    if(!confirm('次の画面に移っていい?')) {
        return false;
    }
});

-HTML
<a data-role="button" href="next.html" id="okButton" >次の画面</a>

クリックイベントがあったらconfirmを呼んで、Cancelを押された時はfalseを返すようにすれば次の画面には行かない。

■同じようなノリでnotification.confirmを使った場合(ダメな例)


-JavaScript
$('#okButton').click(function(){
    navigator.notification.confirm(
        '次の画面に移っていい?',
        function(buttonIndex){ // ★押された時の動作
            if(buttonIndex == 2) {
                return false;
            }
        },
        '確認',
        'はい,いいえ'
    );
});

-HTML
<a data-role="button" href="next.html" id="okButton" >次の画面</a>

このとき、「はい」「いいえ」のボタンを押す前に次の画面に行っちゃいます。

なぜか。

公式のAPIドキュメントを読むと、notification.confirmは非同期なんだと。

つまり、上のコードの★に書いた部分を実行する前に、clickイベントが終わってしまいます。

■notification.confirmを使って意図通り動かす場合

-JavaScript
$('#okButton').click(function(){
    navigator.notification.confirm(
        '次の画面に移っていい?',
        function(buttonIndex){ // ★押された時の動作
            if(buttonIndex == 1) { // 「はい」が押された時
                window.location.href('next.html');
            } else { // 「いいえ」が押された時
                // 何もしない
            }
        },
        '確認',
        'はい,いいえ'
    );
    return false; // 念のため
});
-HTML
<a data-role="button" href="#" id="okButton" >次の画面</a>

つまり、勝手に次の画面に行かないようにaタグには次の画面のURLは入れないようにして、コールバック関数の中でムリヤリ次の画面に飛ばす、って感じ。

でもやっぱり気持ち悪いので、別のソリューションがあったら教えてください。
あと、return false;の場所が微妙な気もする。

2013年1月20日日曜日

[PhoneGap2.3.0]PhoneGapでiOS用とAndroid用のコードはそのまま共有できない!

PhoneGapは、HTML+JavaScript+CSSを使ってワンソースでiOSアプリとAndroidアプリが作れるよ、っていう結構凄い奴。

でも、その「ワンソース」っていうのは一から十まで同じソースが使えるわけじゃないから要注意。

まあ、AdMobとかの広告表示用のSDKは、iOS用とAndroid用で別々になってるから普通に分かる。

けど、ハマったのが、PhoneGap APIを使ってる場合は、Android用に作った物をそのままコピペしてMacにコピーしても(その逆も)思惑通りには動かないってこと。
つまり、実は本体部分のHTML・JavaScript・CSSをそのままコピーしたらダメ。

どうやらdevicereadyイベントがbindできないかfireしない。
そうなると、navigator.notification.confirm("メッセージ", function(){// something}, "タイトル");がAndroidでは動いたのにiOSでは動かない、ってことが起きる。

その理由は、phonegap.jsがiOS版とAndroid版で違うためらしい。
iOS用に作る場合はスクリプトを叩いてプロジェクトを作るけど、このときにiOS用に一部変更してるみたい。

こんなことで一日つぶすとは・・・。

2012年10月31日水曜日

パララックス効果を使ったページ作成の第一歩

パララックス効果を使ったページが増えてきて、作ってみたくなったのでサンプルを作った。
http://sample.kyosuke25.com/201210/slide.html

でもこのサンプルはただの第一歩であって「視差」を表現できていないので、このサンプルには「パララックス効果」は使ってない。 

これで十分派手なページになるので、このままでもいいように思うけど。

ちなみに、複数の要素を違ったスピードで動かして「視差」を表現しないと「パララックス効果」とは言えない気がするけど、単にページ内でダイナミックにスクロールするだけでもパララックスって言ってるようなケースが少なからずある気がする。
 自分もそう呼んでるけど、違和感ありありなので最近パララックスって言うのが憚れる。 

で、肝心の技術要素について。
このサンプルでやってることは大きく3つ。

1.縦3画面×横3画面
2.画面をブラウザいっぱいに表示
3.上下左右斜めスクロール

HTMLはこんな感じ。
<div id="container">
  <div id="area1-1" class="screen">
    <img src="bg1-1.jpg" class="bgimage" />
  </div>
  <div id="area1-2" class="screen">
    <img src="bg1-2.jpg" class="bgimage" />
  </div>
  <div id="area1-3" class="screen">
    <img src="bg1-3.jpg" class="bgimage" />
  </div>
  <div id="area2-1" class="screen">
    <img src="bg2-1.jpg" class="bgimage" />
  </div>
  <div id="area2-2" class="screen">
    <img src="bg2-2.jpg" class="bgimage" />
  </div>
  <div id="area2-3" class="screen">
    <img src="bg2-3.jpg" class="bgimage" />
  </div>
  <div id="area3-1" class="screen">
    <img src="bg3-1.jpg" class="bgimage" />
  </div>
  <div id="area3-2" class="screen">
    <img src="bg3-2.jpg" class="bgimage" />
  </div>
  <div id="area3-3" class="screen">
    <img src="bg3-3.jpg" class="bgimage" />
  </div>
</div>

では順番に。

1.
div#container {
  width: 300%;
}
div.screen {
  width: 33.33333333%;
  float: left;
}
つまり、全体として3倍の横幅を取っておいて、1画面の領域には3分の1の幅を指定。
なお、小数点が第何位まで有効なのかは不明。

2.
div.screen .bgimage {
  width: 100%;
}
1で指定した領域いっぱいに画像幅を指定。

3.
http://d.hatena.ne.jp/KAZUMiX/20080418/scrollsmoothly
にある「scrollsmoothly.js」っていうスクリプトを使わせていただいた。
作者、天才。

ほな。

【追記】
スクロールのパターンを追加した。
1.横スクロールのみ
http://sample.kyosuke25.com/201210/slide_yoko.html
2.斜めスクロールのみ
http://sample.kyosuke25.com/201210/slide_naname.html

2012年3月31日土曜日

FacebookのGraph APIを使った時に付いてくる"#_=_"とjQuery Mobile

FacebookのGraph APIを使って認証をして元のページに戻ってきた時に、URLパラメータに"#_=_"という謎の文字列がくっついてくるときがあります。

常に付いてくるわけではないのが厄介で、getLoginUrlの引数にredirect_uriがないからとか書いてるところもあるけど、ちゃんと書いてても付いてくるときがあり、結局取れないよね、というのが共通認識らしい。

で、大概の場合、それが付いていても影響はないけれど、jQuery Mobileを使ってる時に画面が表示されなくなる(正確には、レンダリング中に処理が止まる)問題が出たので、対策を調査。

下のコードを埋め込めばOK。

<script type="text/javascript">
if (window.location.hash == '#_=_')window.location.hash = '';
</script>

なんかムリヤリでイヤやけど、見る限りこれしか対策見つからず。

2012年3月10日土曜日

Facebook SDK for Android を使って、ダイアログを使わずにウォールにポストするコード例

Facebook SDK for Android に同梱されているサンプルには、ウォールにポストする方法としてダイアログを一旦表示させてそこにポスト内容を書かせてから投稿、というパターンしか見つかりませんでした。

でも、「ねちゃったー」みたいに何かしらの動作により裏で自動的にポストがしたい場合には、そのサンプルだと実現できません。

なので調べましたが、どんぴしゃのものが見つかりませんでした。

というわけで、いろんなサンプルを見ながら試行錯誤しているうちに動いたので、備忘録および共有のために書きました。

要は、SDKのAsyncFacebookRunner#requestというメソッドを叩けばいいのですが、ちゃんとした説明がない!
検索して見つけたサンプルも前のバージョンでパラメーターの数が違ったりとか。

お好きなようにお使いください。

なお、SDKのバージョンナンバーが見当たらないのですが、2012/3/10 時点で最新のバージョンを使ってます。


public class ReturnActivity extends Activity {

    Facebook facebook = new Facebook(Constants.FACEBOOK_APP_ID);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.thanks);

        FacebookSessionStore.restore(facebook, this); 

        AsyncFacebookRunner runner = new AsyncFacebookRunner(facebook);
        Bundle params = new Bundle();
        params.putString("message", "Activityからポストするテスト");
        params.putString("access_token", facebook.getAccessToken());
        runner.request("me/feed", params, "POST", new RequestListener() {

          @Override
            public void onMalformedURLException(MalformedURLException e, Object state) {
                e.printStackTrace();
            }

            @Override
            public void onIOException(IOException e, Object state) {
                e.printStackTrace();
            }

            @Override
            public void onFileNotFoundException(FileNotFoundException e, Object state) {
                e.printStackTrace();
            }

            @Override
            public void onFacebookError(FacebookError e, Object state) {
                e.printStackTrace();
            }

            @Override
            public void onComplete(String response, Object state) {
                // do nothing.
            }
        }, null);
    }

2012年2月24日金曜日

Android標準ブラウザ+Ajax Upload(fileuploader.js)でファイルアップロード

Androidの標準ブラウザは <input type="file" .... ファイルアップロードができるとかできないとか、色々情報があったのでとりあえず残しておくことにしました。

結論としては、できます。
(Androidのバージョンによるっぽく、エミュレーターでは2.2以上でOKでした。)

で、それじゃしょーもないので、Ajax Uploadを使ってみようと。
Ajax Uploadは <input type="file" .... を使ったファイルアップロードをajaxを使って非同期で実行できるライブラリです。

結論としては、そのままじゃ無理。

どうも、fileSizeとかsizeでファイルのサイズが取れないらしく(サイズが0とみなされる)、ファイルサイズチェックの部分でエラー判定されます。

なので、多分そのエラーチェックが呼ばれる場合に本当にサイズが0のファイルを扱うことになるのはレアケースでしょうから、無理やりサイズを入れる変数に適当な数字を入れました。
そしたら動きました。

以上です。

追記(2012/3/10)
2.2の方でもできない場合があり、ブラウザを変える(標準ブラウザ→Dolphin)とOKという報告もありました。