2014年12月9日火曜日

有料プレスリリースをしてみました。

みなさまごきげんいかがでしょうか。

京都はもう本格的に冬の寒さでございます。

さて、前回までCloudkitを使って開発をしていた時の備忘録ブログのようになっておりましたが、結局とのところ、Cloudkitを使ってアプリを申請しますとなぜかCloudkitからデータ取ってこれまへんで。。ゆうてアプリがリジェクトされてしまいました。全く原因不明なので、早々にCloudkitを諦め、HerokuでRailsからデータをJSONで取ってくる仕様にサクッと変更いたしました。。

しかしながら、Cloudkitを完全に諦めたわけではございませんので、また機会があればチャレンジしてみたいと思います。

さてさて、今回は表題の通りプレスリリースについてです。

弊社初リリースアプリであるTaskPortProがリリースから3年、ようやく無料版合わせて1万本のDL数に届きそう、、ということでして、通常価格500円のTaskPortProを3.0のリリースに合わせて無料セールしちゃおう。。という事になりました。

で、いちどこの機会にプレスリリースとやらがどれくらいの効果があるのか、、というのを実験してみようと思い、実行に移してみました。

んで、無料セールを11/21に開始したのですが、その後に思いついたのでセール開始から少し経ってから、、ということもありこれが少し普通のパターンとは違うかもですがご容赦を。

まず、利用したのは某アプリに特化したプレスリリースの会社さんです。
プランとしては、自分でリリース文章を考える(添削はしてくれる)プランと、文章もお任せのプランです。今回は自分で考えるスタンダードなプランで申し込んでみました。
価格は39,800円です。これが高いのか安いのか。。。はよくわかりませんが、他の会社とくらべてみてもこんなもんといえばこんなもんのようです。

送付していただけるメディアの数は約50メディア。これも多いのか少ないのか謎ですが、アプリメディアに特化しているのでこんなものなのでしょう。

結果としてですが、50メディアへの送付で掲載は4メディアでした。私が見逃している可能性もあるので、もう少しあるかもしれません。

ということで、プレスリリースとしての効果は今のところ少し微妙。。という所かなと思います。

ただしこれはもちろんアプリ自体が新規リリースのアプリではなく、単なる無料セール、、ということも大いに関係しているかと思います。500円という少しアプリとしては高めのアプリで、今までほぼ無料セールをしてこなかった、、というのもありますが、そもそもの認知度が全く無かったので、やはりメディアのライターの方もあえて記事にしよう、、というほどのものではなかったかなとも思います。

あと、タイミングの悪い事に同日に、Appleのお薦めアプリにも入っていたThingsという人気ToDoアプリが通常1000円のところを無料セールを開始していた。。というのもあります。

で、プレスリリース単体としては目に見える効果は無かったわけですが、無料セールを行った事自体は効果はありました。

まず、特に何もしていないのですが、セール初日の11/21にAppBankとExcite,Yahooのアプリのところに無料セール情報が掲載されました。こちらは、機械的にやっているのかもしれませんが、これがかなりガツンとDL数を伸ばしました。特にAppBankは影響が高いのでかなりの効果があったみたいです。あと、おそらく海外でも自動でセールスを掲載する系のメディアがあると見えて、DL数の半分くらいは海外からでした。

ということで、DL数のグラフを見てみましょう。


ということで、見事に11/21を頂点とした鋭角な山となっております。。
今まで2000本しかDLされなかったTaskPortProですが、この期間だけで2万本くらいのDLとなりました。やはり無料セール自体は効果はある模様です。ちなみに、この鋭角な山の時は他のアプリも釣られてDL数が伸びました。やはり無料セールはタイミングを見極めてやるべき。。ということですね。

有料プレスリリースの方ですが、値段なりの価値は無いという判断を下すのは尚早ではありますが、どちらにしてもやはりアプリ自体の価値や魅力による、、という事なのでありましょう。ですので、大したことの無いアプリをプレスリリースでなんとか・・・!という事にはまったくならない、、という事です。やはり、素敵なアプリを開発し、そのプロモーション手段として真っ当にプレスリリースを打つ。。というのが王道なのであろうと思いました。プレスリリース自体がカンフル剤になる、、ということはまあ無いのかなとも思います。

さて、次回はroom6で出すゲームアプリ「とっとこダンジョン」の方のプレスリリースを打ってみようと思います。現時点では予約トップ10に掲載しているのみです。いまのところ、予約数はiOS/Androidで400前後づつ、、といった所。無名ディベロッパーで予約特典も無いゲームにしてはまあまあかなと思います。こちらのプロモーション施策もいろいろ行ってみて、また記事にしてみようかなと思います。

ところで予約トップ10に掲載?したからかどうかはわかりませんが、各Ad会社からAd掲載のセールスのメールなどが送られてくるようになりました。営業さんもいろいろな所をチェックされているのですね。

ではまた。



2014年11月14日金曜日

CloudKitでページング読み込み

皆様こんばんわ。
京都はすっかり朝夕冷え込んできまして、紅葉シーズン真っ盛りです。

さて、色々とスッといかないCloudKitさんですが、懲りずにまだやってます。

というわけで、今回はページング処理についてです。
前回も書きましたが、CloudKitはCKDatabase.perfomQueryにて一回で取ってこれる行数が100行までとなってます。少ない行数のクエリでしたらコチラのほうが楽ちんですが、普通はコレでは色々困るかと思います。

で、100件毎ページングしながら取ってくる、、という処理にするのですが、もちろん上のCKDatabase.perfomQueryでも自前でページング処理を書けば動きます。が、そんなの面倒くさい、、ということでCKQueryOperationの登場です。

簡単なサンプルを書きます。
------------------------------------------------------
// CKQueryCursorをクラス変数に持ちます
var cursor:CKQueryCursor?
// レコードを保持する配列
var records:[CKRecord] = []

func record_search() {
    // データベース接続です
    var db: CKDatabase! = CKContainer.defaultContainer().publicCloudDatabase

    // 条件です。
    var p:NSPredicate = NSPredicate(format: "id > 0")!

    // TableNameからレコードを取得します
    let q : CKQuery = CKQuery(recordType: "TableName", predicate: p)

    // CKQueryOperationの定義です
    var queryop : CKQueryOperation
    
    // ★ここがポイント、カーソルをチェックします。
    if self.cursor == nil{
        // カーソルがnil、すなわち最初のクエリ
        queryop = CKQueryOperation(query: q)
    } else {
        // カーソルがある状態(次のレコードを取ってくる)
        queryop = CKQueryOperation(cursor: self.cursor)
    }
    
    // 一回に取ってくる件数
    queryop.resultsLimit = 100
    
    // フェッチ毎の処理を書きます
    queryop.recordFetchedBlock = {(record:CKRecord!) -> Void in
       // 配列にCKRecordをAdd
        self.records.append(record)
    }

    // すべてのフェッチが終わった後の処理を書きます
    queryop.queryCompletionBlock = { (cursor:CKQueryCursor!, error:NSError!) -> Void in
        // カーソル状態を、クラス変数のカーソルに保持します。
        self.cursor = cursor
        // UITableViewのリロード処理
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
            self.tblView.reloadData()
         })
    }        

    // dbに上記のCKQueryOperationをセットします。
    self.db?.addOperation(queryop)
}

------------------

という感じで、上記のようなメソッドを初期処理で呼ぶと最初のレコード100件が、そして、たとえばTableViewの下端に差し掛かった時に同じメソッドを読んでやれば次の100件を再度積み上げて行ってくれる、、、といった感じです。どうでしょう割とスッキリですね。

しかし、いまこのソースをテストしてみたら、Maxまでカーソルをフェッチしたらまた最初からレコードを繰り返し読んできて再度積み上げてくれる、、、という感じになってしまってます。今日はもう帰って晩御飯を作らないといけないのでまた次回までにバグを直します。ではさようなら。


2014年11月6日木曜日

CloudKitハマりどころその3

おはようございます。

さて、めっちゃお手軽ですよ〜という顔をしておいてめっちゃ面倒くさい事連発のCloudkitさんですが、まだまだハマりどころがございます。

まずはクエリーです。Cloudkitからデータを取ってくる時は、


CKDatabase.performQuery()

を使います。しかしこいつがちょっと曲者で、実は全件取ってきてくれません。
正確に言いますと100件までしか取ってきてくれません。ちょっと前まで400件取ってきてくれてたのですがいつのまにか100件になりました。

実はちゃんとリファレンスにも書いてありました。

------
Do not use this method when the number of returned records is potentially more than a few hundred records. 
but to get the entire set of records you must use a CKQueryOperation object instead

-------

ということで、たくさんレコードを取得したい場合やページング処理を行いたい場合なんかはCKQueryOperationを使えとの事です。こちらの使い方はまた調査してみます。

次はRecordTypeのセキュリティです。
いつのまにか、実機に入れたアプリからDefaultContainer以外のデータベースへの書き込みが失敗するようになりました。なんでかなーと思っていたらいつのまにかダッシュボードが下のような感じに変更されていたようです。















RecordTypesの右上にSecurityという設定項目が、、、こいつのAuthenticatedのWriteにチェックをいれてやらないとPublicであっても実機からの別コンテナーへの書き込みがエラーとなるようです。
★端末にiCloudの設定をしていない場合は、このチェックを入れていてもおそらくエラーとなります。


というわけで、まだまだ出てきそうですがとりあえずは読み書きは出来るようにはなっております。

ではまたごきげんよう。。

2014年10月28日火曜日

CloudKitハマりどころその2

お疲れ様です。

さて、前回はコンテナーという概念があるのと、あとシミュレーターでもちゃんとiCloudのアカウント登録しとかんと動かへんのよ。。というお話をしました。

次はCloudKitのデータの登録についてです。

基本的にCloudKitのテーブルを構成したりするのはCloudKit Dashboardという、デブ専から行けるWebベースの画面から行います。しかしこのCloudKit Dashboard、CSVとかからインポート出来たりとかそんな親切機能はございません。1つ1つデータは手入れです。

そんな事はやってられないので、アプリからコネコネしてデータを入れる事をやっているのです。まあ、それはなんとかなります。

で、あとは本番環境へDeployだ!と言うところですが。。CloudKit DashboardにはDeploy to Productionというボタンがあって、これでスキーマとデータを移してくれるんよねホイ?っと思ってたら、、そんなに甘くはありません。まあ当たり前ではありますが移るのはスキーマだけでした。。

さて、どうやって本番環境にデータを?と言うことでいろいろやってみました。

・リリースビルドしてシミュレータから本番にから送り込む → 駄目でした
・リリースビルドしてiPhone実機繋いでRunして実機から送り込む → 駄目でした
・リリースビルドしてipa作って実機にインスト、そっから送り込む → OK!!

実はipaにArchiveする時に「iCloud Container Environment」を選べる画面が出て、
そこでテストか本番か選べるのでした。。ちゃんちゃん。。


2014年10月24日金曜日

CloudKit解決!

このまま1日坊主で終わってしまいそうな雰囲気だったSwift挑戦記ですが、
無事2日めに突入出来そうです。

さて、前回CloudKitが全くもってクエリを返してくれないという事で難儀しておりましたが、またもやK君の力添えにて解決。

まずハマりポイントその1

CloudKitにはContainerという概念があります。まあスキーマを保存する入れ物でしょうか。普通のRDBですとデータベースというレイヤーに当たる所だと思います。

んで、今回はCloudKit + Today Extensionという組み合わせで作っていたために、CloudKit側に本体とExtension2つのContainerが出来ていました。

よく分かっていなかったのでCloudKit DashboardにてExtension側にデータを突っ込んでいたのですが、、、

var db: CKDatabase! = CKContainer.defaultContainer().publicCloudDatabase

ネットからかっぱらってきたこのソース、よく見るとDefaultのContainerを取ってくる用でした。設定の方で、他のContainerを指定してから、、










var db: CKDatabase! = CKContainer(identifier: "iCloud.com.subakolab.@@@@@@@@@").publicCloudDatabase

という風にソースを変更してやります。(@@@@@@@@@はContainer名)

そして次のソース

//
let p = NSPredicate(format: "TRUEPREDICATE")
let q : CKQuery = CKQuery(recordType: "※テーブル名", predicate: p)        
db.performQuery(q, inZoneWithID: nil) { (results, error) -> Void in
    self.texts = results as [CKRecord]
    self.tableView.reloadData()
}

これでUITableViewにレコードが表示出来るはず。。。。が、いくらやってもサーバからエラーしか返ってきません。。な。。。ぜ。。。だ。。。。

ここでハマりポイントその2




















CloudKitはiCloudにログインしていないと使えないサービスです。
(2014-11-07追記 ★ログインしなくても実機ではReadは出来るみたいです。ただし、やはり何故かシミュレーター上ではiCloudの設定は必要なようです。)

なので、、、当然iOS Simulator上でもiCloudにログインしていないと使えないのでした。。当たり前ですがこれに気づかず。。。

というわけで、これで無事データを取ってくる事が出来ました。

サーバの用意いらず費用いらずの素敵MBaaSサービスのCloudKit、これから色々活用出来そうです。ただ、DashboardがデータのImport/Exportも出来ないなど使い勝手は本当に最低限なので、そのあたりが充実する事を切に願う次第であります。

またそのうち続きを書きます。

では。。


2014年10月1日水曜日

Xcode6 + Swift挑戦記 その1

大変ご無沙汰しております社長です。

さて、やらなければいけないこと満載の最中ですが、現実逃避のために
Xcode6+Swiftでアプリを作ってみることにしました。

今回はiOS8のCloudKitとTodayExtensionを使った、モンスターストライク(©mixi)の降臨チェックウィジェットアプリを作ってみる事にしました。完全に個人的に欲しいがために作ります。

まずはXcode + Swiftで本体側のアプリをつくります。

本体側の構成は、TabViewControlerで各テーブルを操作するような感じです。なので、一覧表(TableView)と単票(ScrollView)の組み合わせみたいな感じ。

まずはTableViewに固定データを出す所からドハマり。
詳細はまたいつか書く。

次、ScrollViewでハマる。スクロールしません。
詳細はまたいつか書く。

なんやかんやで社員K君の助けにて両方解決。

さて次はCloudKitです。
はい、うまくいきません。
CKDatabase.performQueryをぶっこみますが、
errorが帰ってきます。CKErrorDomain : code:7 と。。。
なんですかcode7って。

完成は遠そうです。


2014年1月10日金曜日

新年あけましておめでとうございます

本年もどうぞ宜しくお願い致します。

周囲の想像どおり3日坊主化していたブログですが、今年はアウトプットの年ということで、なんとか毎日とは言わずとも週1では書いていこうと固く心に誓ったのであります。

お仕事の方は相変わらずバタバタバタバタしております。
今年は2月に某ぶっとい書籍系なアプリをリリースする予定です。某なのは請負のお仕事だからです。結構ビッグなタイトルです。昨年秋からK君M君2人で命を削りながらコツコツコツコツ作っていって、ようやくゴールが見えてまいりました。。
同時にもうひとつ某ぶっとい書籍系アプリもリリースです。最近こちらの書籍版についての記事がTwitter界隈やネットニュース界隈を少し賑わしておりましたので、タイムリーなうちにリリースしたいところ。。

次は1年前から進めていた写真系アプリの方が、昨年秋に急に大型タイアップが決まりまして沈黙状態から急にバタバタバタバタ〜っと進行しております。こちらもまだ詳細は書けないのですが、アプリリリース自体は1月下旬の予定、タイアップ発表は来月初旬の予定です。はやく詳細を書きたい所ですが我慢我慢。。リリース自体は弊社ブランドではないですが、こちらは社名を出して良いとの事ですので、リリース後は盛大に宣伝していければと思ったりしております。同類アプリも立て続けに出していければと計画しており、ちょっと個人的に熱い感じになってきております。

自社タイトルのアプリとしては、秋に少し表のブログに書いた「たまぴんびゅーん」がようやくリリース間近。ところがお試し申請を出してみたところ、毎度おなじみのMetadataリジェクト。。でもまあ大丈夫でしょう。来月には出せるかなと思っています。
こちらroom6ブランドで出します。room6はうちのアパートの6号室で開発しているエンターテイメントアプリのブランドです。萌え系アプリを出そうということでブランドを変えましたが、まあ今となってはそれはどうでもいいのですけども、今年はゲームもK君の手によって立て続けにリリースしていく予定!!

ゲームですが、最近社内では「ドミニオン」がプチブーム。
個人的にも家で子供とカードゲームを遊んでいまして、やはりこの方面が熱いです。
まだこういったカード・ボードゲームでアプリの方のヒットと呼べるものは無い気もしますので、ガンガン狙っていければと思っている今日このごろ。

他にもいくつかの請負案件が並行で進んでいて、人は少ないくせになんだかバタバタと忙しい状態というのがずっと続いております。それもあって、久しぶりに僕も開発をする予定。まいどおなじみのRailsですけども。そろそろiOSのアプリが作りたいです。小ネタを色々仕込んでるので、時間作って作ろうと企んでいるのですがなかなかまとまった時間が。。毎日メールやら経理やら電話やら調整やらでいつの間にか日が暮れます。

たぶんカッコイイITベンチャーの社長さんからするとかなりイケてない仕事っぷりなのですが、また社長の仕事っぷりについては何か書けたらなと思いつつ、気がついたら保育園のお迎えの時間が近づいてきたのでこのへんで。