Techracho

MusicFly v2.2.3リリース XperiaMini対応

このエントリーをはてなブックマーク Share
2010.07.30    MusicFly, android, java, プレスリリース, 芝原   タグ: , , , , , —    shibachan   

弊社BPSで開発しておりますAndroid端末向け音楽試聴アプリMusicFlyを先ほど1週間ぶりにアップデートしました。

今回のアップデートにより

XperiaMiniに代表される低解像度端末や、反対の高解像度端末などへの対応を果たし

全スクリーンサイズ対応のアプリケーションとなりました。

技術者向けの参考情報

また、以前より原因が解明できずにいたバグのいくつか解決することができました。

そのうちの一つがAndroid1.5でのみタブを利用した画面で強制終了してしまうクリティカルなバグであり、

今回無事解決しました。技術者向けの詳しい話はこちらで。

該当端末を利用している方にはご不便おかけしました。

Android 1.5でTabHostを使った場合、StackOverflowErrorが発生する

このエントリーをはてなブックマーク Share
    android, java, 馬場   タグ: , , , , —    baba   

Androidで便利な、タブ表示。

タブ表示

タブ表示

これは、TabActivity, TabHost, TabSpecを使って簡単に実現できます。

src/MainActivity.java

package jp.bpsinc.android.tabtest;

import android.app.TabActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;

public class MainActivity extends TabActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    TabHost tabHost = getTabHost();
    LayoutInflater.from(this).inflate(R.layout.main, tabHost.getTabContentView(), true);

    //タブを作る
    TabSpec tab1 = tabHost.newTabSpec("tab1");
    tab1.setIndicator("tab1");
    tab1.setContent(R.id.tab1);

    TabSpec tab2 = tabHost.newTabSpec("tab2");
    tab2.setIndicator("tab2");
    tab2.setContent(R.id.tab2);

    tabHost.addTab(tab1);
    tabHost.addTab(tab2);
  }
}

res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent">

  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />
  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB2" android:id="@+id/tab2" />
</FrameLayout>

しかし、サンプルでなく複雑なアプリを作ると、Android 1.5 (SDK Version 3) の時だけ、StackOverflowErrorが発生するという現象に見舞われることがあります。

body : java.lang.StackOverflowError
at android.text.TextUtils#getChars:69
at android.graphics.Canvas#drawText:1278
at android.text.Layout#draw:337
at android.widget.TextView#onDraw:3921
at android.view.View#draw:5838
at android.view.ViewGroup#drawChild:1486
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.view.ViewGroup#drawChild:1484
at android.view.ViewGroup#dispatchDraw:1228
at android.widget.AbsListView#dispatchDraw:1319
at android.widget.ListView#dispatchDraw:2820
at android.view.View#draw:5944
….

こちらのGoogleGroupディスカッションでも触れられているようですが、Android 1.5では、タブの中に多重にネストしたコンテンツがあると、StackOverflowErrorが発生します。

手元のエミュレータで試したところ、12回ネストしたところで、エラーになりました。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent" android:layout_height="fill_parent">

  <TextView android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="TAB1" android:id="@+id/tab1" />

  <FrameLayout android:id="@+id/tab2" android:layout_width="fill_parent" android:layout_height="fill_parent">
    <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
      <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
        <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
          <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
            <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
              <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                  <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                    <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                      <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                        <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent">
                          <TextView android:text="TAB2" android:layout_width="wrap_content" android:layout_height="wrap_content" />
                        </LinearLayout>
                      </LinearLayout>
                    </LinearLayout>
                  </LinearLayout>
                </LinearLayout>
              </LinearLayout>
            </LinearLayout>
          </LinearLayout>
        </LinearLayout>
      </LinearLayout>
    </LinearLayout>
  </FrameLayout>
</FrameLayout>

XMLをパーツに分けて書いていると、うっかり12回を超えてしまうことがあるので、注意が必要です。
解決策としては、ネスト回数を減らすか、Android 1.5を対象から外すという後ろ向きなものが最適ですね。

AndroidのパーミッションWRITE_EXTERNAL_STORAGE

このエントリーをはてなブックマーク Share
    android, 馬場   タグ: , , , —    baba   

MusicFlyなどの弊社Androidアプリで、SDカードを使うようには見えないのに

ストレージ:SDカードのコンテンツを修正・削除する

のパーミッションが付与されていて、不安に思う方がいらっしゃったようです。

技術的な話ですが、該当のWRITE_EXTERNAL_STORAGEは、API Level 4(Android 1.6)以上で追加されたもので、Android 1.5の時には、パーミッション無しでSDカードに書き込めました。

Androidでは後方互換性のために、TargetをAndroid 1.5にしたアプリを1.6以上で動かすと、自動的にWRITE_EXTERNAL_STORAGEパーミッションが付与される、というようになっています。

これが、やたら多くのアプリが「ストレージ」パーミッションを要求する理由ですね。実際には書き込みしていないです。

ちなみに、MusicFlyでそれぞれのパーミッションの利用方法は以下の通りです。
READ_PHONE_STATE : 着信時に音楽を停止する機能で利用
KILL_BACKGROUND_PROCESSES、RESTART_PACKAGES : メニューから「終了」を実施するために利用

KILL_BACKGROUND_PROCESSESは、自分だけを終了したいのに範囲が広すぎますね。
Froyo以上対応にすればもう少しましな解決ができるんでしょうけど・・・。悩ましいです。

※MusicFlyではXperia miniなどのQVGA端末に対応するため、Targetを1.6にしつつ1.5でも動作するように調整しています。
 そのため、次期バージョンでは、「ストレージ」パーミッションが消えているかもしれません。MusicFly2.3をお楽しみに!

RailsサーバUnicornを飼いならす! 運用時の便利技

このエントリーをはてなブックマーク Share
2010.07.28    Ruby, Ruby on Rails, 伊藤   タグ: , , —    tomotaka   

伊藤です。

前回ブログで紹介したRailsサーバUnicornくんを運用し始めて結構時間が経ちました。
サービスを落とさないであるとか、システムの安定性を確保するために、
ちょっとしたユーティリティを作ったり監視ソフトMonitの設定を行ったりしていました。

みなさんのお役に立つかわかりませんが、弊社でUnicornと組み合わせて運用に利用しているツールや設定をブログに掲載してみたいと思います。
もっといいやり方がありましたら、ぜひコメント欄でご紹介頂ければと思います。

ダウンしたら自動的に再起動

これはMonitで行っています。
もちろん同内容の監視ツールGodでも可能だと思いますが、以前設定した経験があって設定が楽そうだったので、Monitでやってみました。(事実楽でした)

check process unicorn with pidfile "/path/to/rails/tmp/pids/unicorn.pid"
  start program = "/home/tomotaka/monitor/unicorn_start" with timeout 10 seconds
  stop program = "/home/tomotaka/monitor/unicorn_stop"
  if 2 restarts within 3 cycles then timeout
  if cpu usage > 95% for 3 cycles then restart

とりあえず, コピペで使う際に変更しなければいけない箇所は

  • check processのあとの監視タスク名(なんでもよし, unicornを1個しか走らせてないならunicornでいいかも?)
  • start program(後述)
  • stop program(後述)

お分かりかと思いますが、Unicorn起動/停止のためのコマンドは自作しました。
startは簡単なシェルスクリプトです。

#!/bin/bash
UNICORN_RAILS_BIN=/usr/local/bin/unicorn_rails
MY_RAILS_ROOT=/path/to/rails
MY_UNICORN_CONFIG=config/unicorn.rb
MY_RAILS_ENV=production

pushd $MY_RAILS_ROOT
$UNICORN_RAILS_BIN -c $MY_UNICORN_CONFIG -E $MY_RAILS_ENV -D
popd

簡単ですね。コピペで使う際は各変数を書き換えればオッケー。しいて言えばMY_UNICORN_CONFIGはRAILS_ROOTからの相対パスであることに注意でしょうか。(ディレクトリを移動してからコマンドを発行してるため) こういう簡単なツールを組み合わせて便利に使えるのがコンピュータのいいところですね。

unicorn_stopはUnicornのマスタープロセスのPIDをしらべて、それに対してQUITシグナルを送ればよいですね。シェルスクリプトでも出来るシンプルな内容ですが、unicornのプロセス制御のためのライブラリを作ったので、それを使ってやってます。(ライブラリについては後述)

require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))

rails_root = "/path/to/rails"
pids = UnicornManager.get_unicorn_pids(rails_root)

puts "Sending signal to unicorn master [pid=#{pids[:master]}]"
Process.kill :QUIT, pids[:master]
puts "OK"

unicorn_manager.rbというのがライブラリですね。UnicornManager.get_unicorn_pidsというメソッドでUnicornのPID情報をハッシュ形式で返してくれるので、その情報をもとにProcess.killでシグナルを送ってます。unicorn_manager.rbについては、次の自動再起動の項で触れます。unicorn_manager.rbを同じディレクトリにおいて、rails_root変数を書き換えれば動作するはずです。

とりあえず、ライブラリunicorn_manager.rbと、上記のstart/stopコマンド2点があれば

  • unicornが突然死したら自動的に起動
  • unicornがCPU食い過ぎてたら自動的に再起動
  • unicornがメモリ食い過ぎてたら自動的に再起動

などのタスクがMonitだけで完了します。
その他の複雑な条件も設定できる懐の深さがMonitにはありますので、ぜひ一度Monitのドキュメントに目を通してみてください。

これでとってもハッピーになれそうな感じですが、現時点のMonitにはstop programとstart programしかなく、”再起動”も”停止” => “起動”で実現される点が気になりました。というのもUnicornを使用するメリットのひとつはダウンタイムを作らずに子プロセスを新しく生まれ変わらせることができる点です。そのため、メモリを食べ過ぎて太っちゃった子プロセスにQUITシグナルを送るプログラムを先ほどunicorn_manager.rbというプログラムを作成してcronで利用しています。

メモリ使用量の多い子プロセスを定期的にrespawn

というわけで, fat-memory-process-killer.rbです。物騒な名前ですね。

#!/usr/local/bin/ruby
require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))
require "logger"

logfile = "/path/to/logdir/fat-memory-process-killer.log"
loglevel = Logger::DEBUG # Logger::INFO if this script get enough stable
rails_root = "/path/to/rails"
threshhold = 40 # MB

# ----- end of config -----

puts "fat-memory-process-killer started at #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}"

logger = Logger.new(logfile)
logger.level = loglevel
logger.info "----- Start -----"
memory = UnicornManager::get_memories(rails_root)
logger.debug "** rails_root=#{rails_root}"
logger.debug "** threshhold=#{threshhold}MB"
logger.info "Got PIDs: m=#{memory[:master].keys} c=#{memory[:children].keys.join(",")}"
mpid = memory[:master].keys[0]
mmem = memory[:master][mpid]
logger.debug sprintf("** master-memory: % 7d => %4.2fMB", mpid, mmem.to_f/(1024*1024))

# kill fat child
memory[:children].each do |pid, mem_size|
  logger.debug sprintf("** child-memory:  % 7d => %4.2fMB", pid, mem_size.to_f/(1024*1024))
  if 1024*1024*threshhold < mem_size then
    logger.info "Sending QUIT signal to child(pid:#{pid}) memsize=#{mem_size} > threshhold(#{1024*1024*threshhold})"
    Process.kill :QUIT, pid
  end
end

logger.info "Finish"

デーモンにすると面倒なことが多いので、5分間隔でcronで実行しています。コピペで利用するには、 end of configより上の部分を書き換えて、unicorn_manager.rbを同じディレクトリに置けば動作するはずです。このプログラムの働きぶりを観察するためにloggerでログに結果を出力していますが、興味がなければlogger関係のコードは削ってしまってもいいかもしれません。

いちおうこんな感じで報告されます。使用メモリが指定した40MBを超えたプロセスが3ついたので、QUITされてるようです。

I, [2010-07-27T11:00:02.734795 #1161]  INFO -- : ----- Start -----
D, [2010-07-27T11:00:02.994152 #1161] DEBUG -- : ** rails_root=/var/www/music-fly.net/webservice2
D, [2010-07-27T11:00:02.994369 #1161] DEBUG -- : ** threshhold=40MB
I, [2010-07-27T11:00:02.994444 #1161]  INFO -- : Got PIDs: m=13550 c=31905,748,30108,980,32380,30389,29861,981,745,31898,30105,746,31679,30106,747,417
D, [2010-07-27T11:00:02.994639 #1161] DEBUG -- : ** master-memory:   13550 => 30.49MB
D, [2010-07-27T11:00:02.994680 #1161] DEBUG -- : ** child-memory:    31905 => 35.09MB
D, [2010-07-27T11:00:02.994720 #1161] DEBUG -- : ** child-memory:      748 => 33.98MB
D, [2010-07-27T11:00:02.994758 #1161] DEBUG -- : ** child-memory:    30108 => 34.14MB
D, [2010-07-27T11:00:02.994795 #1161] DEBUG -- : ** child-memory:      980 => 46.07MB
I, [2010-07-27T11:00:02.994830 #1161]  INFO -- : Sending QUIT signal to child(pid:980) memsize=48304128 > threshhold(41943040)
D, [2010-07-27T11:00:02.994897 #1161] DEBUG -- : ** child-memory:    32380 => 31.07MB
D, [2010-07-27T11:00:02.994936 #1161] DEBUG -- : ** child-memory:    30389 => 36.44MB
D, [2010-07-27T11:00:02.994973 #1161] DEBUG -- : ** child-memory:    29861 => 45.95MB
I, [2010-07-27T11:00:02.995007 #1161]  INFO -- : Sending QUIT signal to child(pid:29861) memsize=48177152 > threshhold(41943040)
D, [2010-07-27T11:00:02.995049 #1161] DEBUG -- : ** child-memory:      981 => 31.05MB
D, [2010-07-27T11:00:02.995086 #1161] DEBUG -- : ** child-memory:      745 => 31.05MB
D, [2010-07-27T11:00:02.995123 #1161] DEBUG -- : ** child-memory:    31898 => 34.82MB
D, [2010-07-27T11:00:02.995160 #1161] DEBUG -- : ** child-memory:    30105 => 34.49MB
D, [2010-07-27T11:00:02.995197 #1161] DEBUG -- : ** child-memory:      746 => 45.10MB
I, [2010-07-27T11:00:02.995231 #1161]  INFO -- : Sending QUIT signal to child(pid:746) memsize=47288320 > threshhold(41943040)
D, [2010-07-27T11:00:02.995272 #1161] DEBUG -- : ** child-memory:    31679 => 31.50MB
D, [2010-07-27T11:00:03.057719 #1161] DEBUG -- : ** child-memory:    30106 => 36.51MB
D, [2010-07-27T11:00:03.057796 #1161] DEBUG -- : ** child-memory:      747 => 31.52MB
D, [2010-07-27T11:00:03.057835 #1161] DEBUG -- : ** child-memory:      417 => 31.05MB
I, [2010-07-27T11:00:03.057998 #1161]  INFO -- : Finish

ダウンタイムなしでコードをリロードするコマンド

Railsのproduction環境では、新しいコードを動作中のサーバに反映するにはいったんサーバを再起動しないといけません。Unicornもダウンタイムこそ無いものの、マスタープロセスのpidを調べて, USR2シグナルを送るという作業が必要になります。UNIX界で長年暮らしてらっしゃる方はそんなもんpsやawk組み合わせたシェルスクリプトで一発だろ、って感じかと思いますが、僕は軟弱者なのでメモリ食い過ぎプロセスを殺すためにつくったライブラリを利用して、Rubyで作りました。unicorn_reloadコマンドです。

#!/usr/local/bin/ruby

require File.expand_path("./unicorn_manager.rb", File.dirname(__FILE__))

rails_root = "/path/to/rails"
pids = UnicornManager.get_unicorn_pids(rails_root)

puts "Sending signal to unicorn master [pid=#{pids[:master]}]"
Process.kill :USR2, pids[:master]
puts "OK"

unicorn_stopのところで紹介したプログラムとシグナルの名前しか変わってないですね…これはひどい。

unicorn_manager.rb

unicorn_manager.rbのコードも貼付けてやろうかと思いましたが、ちょっと長いのでダウンロードリンクだけにしておきます。

その代わりといっては何ですが、unicorn_manager.rbの機能を紹介しておきます。

  1. Unicornのpidリストを得る: UnicornManager.get_unicorn_pids(”/path/to/rails”) => {:master => 123, :children => [124,125,126,127...] }
  2. Unicornに設定を再読込みさせる(マスターにHUPシグナルを送る): UnicornManager.reload_config(rails_root)
  3. Unicornにプログラムを再読み込みさせる(マスターにUSR2シグナルを送る): UnicornManager.reload_code(rails_root)
  4. Unicornの子プロセスを全て再起動させる(各子プロセスに順番にQUITシグナルを送る): UnicornManager.restart_all_child(rails_root)
  5. Unicornのメモリ使用量をプロセスごとに得る: UnicornManager.get_memories(rails_root) => {:master => {123 => 1000000}, :children => {124 => 1000000, :125 => 1000000, …}}

動作要件:

  • /path/to/railsがRAILS_ROOTとして与えられたとき、/tmp/pids/unicorn.pidにunicornのpidがあること
  • psの出力フォーマットがLinux互換であること

書いてて気づきました。unicorn_stopとunicorn_reloadのコマンドは専用のメソッドがあるじゃないか… もっと短くできますね。

まとめ

Unicornが落ちないような仕組みをMonitで構築した。Unicornの子プロセスがメモリ食い過ぎたらrespawn(日本語でいい表現を思いつかない、再起動とはちょっと違うような…)する仕組みをcronとオリジナルスクリプトで実現した。開発の際に作ったライブラリを使ってコードでプロイ時にも楽できるスクリプトとかも作った。

それではみなさん快適なRailsライフを!

Unicornシリーズ前の記事: 次世代RailsサーバーUnicornを使ってみた

Amazon Kindle 購入しました

このエントリーをはてなブックマーク Share
2010.07.27    馬場   タグ: , , —    baba   

値下げでだいぶ安くなったKindleを購入しました。
Amazon.comのアカウントが必要ですが、2~3日で届くのはすごいですね。

普通の段ボールで到着。

海を渡ってきました

海を渡ってきました

開封すると、電子ペーパーに最初の使い方が表示されています。

開封!

開封!

裏面は銀色です。

裏面 技適マークが付いてます

裏面 技適マークが付いてます

かなり薄くて軽いですね。
また、電子ペーパーは書き換えに1秒ほどかかるものの、本の閲覧は快適だし、マーケットもそれほどストレス無く使えます。
さすがにWebは、最適化されていないものは使いづらいですが。

購入直後に、Dear Takao Babaとか出てきてびっくりしました。
購入者のAmazonアカウントと初めからひもづけてあるので、特に設定せずに本の購入もできる、さすがAmazon。

日本語はそのままだと表示出来ませんが、PDFならある程度は問題ないし、調整すれば色々できそうです。

手元のコンテンツを見やすく表示する調整や、KDKの非公式実装を使った実験などを楽しんでいます。
早くKDKの承認がおりないかな

ブログにブックマークボタンを付けました

このエントリーをはてなブックマーク Share
2010.07.23    馬場   タグ: , , , , , , —    baba   

BPSの開発ブログ(このブログ)や社長ブログに、はてなブックマークやTwitter、Facebookで共有するためのボタンを付けました。

気に入った記事があったら是非クリックして下さい。やるきがでます。

MusicFly 他アプリから起動する

このエントリーをはてなブックマーク Share
    MusicFly, android, java, 芝原      shibachan   

音楽試聴AndroidアプリケーションMusicFlyが先日公開されたバージョン2.2.0より、他のアプリから呼び出すことが可能になりました。

アーティスト名もしくはアルバム名を受け取ってその検索結果一覧画面を表示させることができます。

他アプリケーション

他アプリケーション →

MusicFly

MusicFly

右の画像はサンプルアプリケーションから【hoge】という単語でMusicFlyにアーティスト検索を起動させています。

サンプルアプリケーションのコードを載せておきますので、参考にしていただいて、ぜひとも素晴らしいアプリを開発してください。

        // 入力フィールド
        final EditText editText = (EditText) findViewById(R.id.text);

        // アーティスト検索ボタン
        final Button artistBtn = (Button) findViewById(R.id.btn_artist);
        artistBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // 入力フィールドのテキストを取得
                String input = editText.getText().toString();

                // アーティスト検索を実行
                Uri uri = Uri.parse(String.format("musicfly://search?type=artist&name=%s", input));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });

        // アルバム検索ボタン
        final Button albumBtn = (Button) findViewById(R.id.btn_album);
        albumBtn.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                String input = editText.getText().toString();
                Uri uri = Uri.parse(String.format("musicfly://search?type=album&name=%s", input));
                Intent intent = new Intent(Intent.ACTION_VIEW, uri);
                startActivity(intent);
            }
        });

ExcelでCSV保存したときに半角スペースがはてな(?)に文字化けする

このエントリーをはてなブックマーク Share
2010.07.22    馬場   タグ: , , —    baba   

ExcelからCSV形式で保存するには、「名前を付けて保存」ダイアログでCSV(カンマ区切り)を選択すればOKです。

#エクスポートしたいところですが、保存しかできないようですね。連続でやるときにはすごく不便。

ところが、これをやると、文字化けが発生してしまうことがあります。

半角スペースが含まれるExcelファイルで、Excel上で見るぶんには問題ないのですが、これをCSVエクスポートすると、1行目だけ文字化けします。
test

見た目は同じだけど上だけ文字化けする

見た目は同じだけど上だけ文字化けする

これは、同じ半角スペースに見えても「CODE=32(0×20)」の「半角スペース」と、「CODE=160(0xA0)」の「NBSP」があるのが原因になっています。
0xA0のNBSPはShift-JISでは表現できないので、保存時に「?」に文字化けしてしまいます。

これを解消するには、160のNBSPを32の半角スペースに一括置換すれば良いです。

やりかた:

適当なセルに「=CHAR(160)」という数式を入力して、それの結果をコピーします。

charcode=160の文字を作成

charcode=160の文字を作成

その後、Ctrl+Fの「置換」から、検索対象にコピーした内容をペースト、置換後の文字に普通の半角スペースを入力して、「すべて置換」すればOKです。

置換

置換

これで、見た目は変わらないけど文字化けしないExcelファイルができました。

というか、普通に使っていればこんな問題は起きないんですが、なぜか送られてきたExcelがこんなことになっていて・・・
先方はどんな使い方をしていたんでしょうね?

型で象るカメラアプリ「カタぞう」iPhone版リリース!

このエントリーをはてなブックマーク Share
    カタぞう, プレスリリース, 馬場   タグ: , , , —    baba   

お待たせしました!

カタぞうのiPhone版が、本日AppStoreで公開されました。

カタぞうiPhone版
http://itunes.apple.com/jp/app/id382218930

インストールしてみた

インストールしてみた

カタぞうは、見慣れた日常の一コマを、思わず笑みのこぼれる一枚に変えられる簡単・シンプルなカメラアプリです。
自由にテンプレートをアップロードでき、楽しみ方は無限大。

是非カタぞうをお試し下さい!

音楽試聴Androidアプリ MusicFly v.2.2.0リリース!!

このエントリーをはてなブックマーク Share

先ほど音楽試聴Androidアプリ MusicFlyをバージョン2.2にアップデートしました!!

新バージョンの主な特徴は、

  • 楽曲の購入をより分かりやすく
  • Tweitterとの連携を強化
  • 他アプリからの起動が可能

となっています。

楽曲の購入をより分かりやすく

楽曲の購入をより分かりやすく

楽曲の購入をより分かりやすく

MusicFlyは音楽試聴アプリであり、試聴していただき気に入ったものがあれば購入していただくことを目的としています。
しかし、ユーザーの方々から購入遷移がわかりずらいとの声をいただき、それを解消するため、今回のアップデートでより分かりやすい仕組みを導入しました。気に入ったアルバムがあれば再生画面の【Buy Now】ボタンからお願いします。

Tweitterとの連携を強化

Tweitterとの連携を強化

Tweitterとの連携を強化

MusicFlyの主な機能のひとつに気にいったアーティスト、アルバムをお気に入りとしてブックマーク登録できるというものがあります。そして、TwitterとMusicFlyの連携を許可していれば、お気に入り登録時に自動でその旨をつぶやくことができました。
今回のアップデートではこのTwitterとの連携を強化し、お気に入り登録時にTweetするのかしないのか、するならばそのメッセージ内容を編集できるようになりました。

他アプリからの起動が可能

他アプリからの起動が可能

他アプリからの起動が可能

Twitterのあるユーザーさんの発言がきっかけとなり、開発しました。
他アプリから検索キーワードをMusicFlyに投げると、その検索結果を表示できます。
詳しい利用方法は後日別の記事にまとめます。

謝辞

気がつけばMusicFlyもバージョン2.2となり、初期開発から数えると半年以上のプロジェクトとなってきました。ここまでこれたのも、応援、ご協力していただいている多くの皆さまのおかげであり、感謝の次第であります。
そして、今後もよりよいサービスを提供できるよう、ますますの応援、ご協力をよろしくお願いします!!

古い投稿 »

COPYRIGHT [C] 2009 BEYOND PERSPECTIVE SOLUTIONS LTD. ALL RIGHTS RESERVED.