blue_field

技術的なメモとか読書記録とかいろいろ(の予定

RubyMotionでiOSアプリ作ってリリースした

晴れてiOSアプリ童貞を卒業したw

前にも少し書いたのだけど、 週末の空き時間のみを利用して、RubyMotionで小さなアプリを書いていた。 単機能ながらだいぶかかってしまったけど、ようやくリリースまでこぎつけた、ということでエントリ。

PokeBu

PokeBu

  • YUSUKE AONO
  • ニュース
  • 無料

Pocketに突っ込んだ記事を読むアプリで、 はてブのコメントを見たりアプリ内でブックマークできたり記事をアーカイブできたりする。 ただの俺得アプリなんだけど、はてブもPocketもヘビーに使ってる僕と同じような方なら多少役立つかもしれません...
あと、センス無いくせに5分くらいしか時間かけずに作った非常に雑なアイコンなので変えたい

GitHub: ysk1031/Pokebu

モチベーション維持の難しさ

やっぱり週末だけの開発だとモチベーションというのはそう長く続かない。 このアプリも10月くらいから開発しているが、 GitHubのコミットのグラフを見ると、昨年末以降はほとんど触ってなくて、今年の3月に頑張ってやる気出して作りきったのが分かるw

f:id:yusuke_1031:20150506113700p:plain

今回のケースは、単純に自分の欲しいモノを作ろうという「自分の欲しいモノ駆動開発」(?)だったわけだが、 それでも相当強い意志がないとやっぱり飽きるのだなあ、と再確認。 趣味での開発は、1ヶ月くらいで作りきれる分量がやっぱり良いんだろうなあと思う。

今回のアプリも、振り返ってみると書いたコードは大した分量じゃないし、もう少し短いスパンで絶対作れた。 何か作り始めたら他の分野の学習などにはいったん手を出さず、一気に作りきるほうが良いのかも。

リジェクト2回

iOSアプリを出す際に避けられないのがApple様のアプリ審査。 審査ももちろん初体験だったのだが、リジェクトを2回くらった。

1回目は完全な凡ミスで、デモ用のテストアカウント(Pocket・はてなのID & パスワード)を貼り忘れたというもの。 レビュー待ちに8日かかってのリジェクト理由がこれなので、だいぶ萎えたというか自分の無知を呪ったw

2回目は、ログイン周りがユーザー体験的にダメだということでリジェクト。

Upon launching the app, a web page in mobile Safari opens for logging in with a Pocket account, then returns the user to the app. The user should be able to log in without opening Safari first.

上記のような理由。 今回作ったアプリはPocketでのログインが必須で、 その実装にはPocketのSDKを利用している。 このSDKによるログインだが、デフォルトの状態ではPocketのアプリがインストールされてないとSafariに遷移し、 そちらのWeb画面でログインすることになる。 ここがダメで、アプリ内でログインを完結できるようにせよということらしい。 SDKレポジトリのissue見ると同じ問題に当たった人がいて、解決した方法も載っていたので真似した。

iOS App using Pocket-ObjC-SDK is rejected because of OAuth login with Safari. · Issue #9 · Pocket/Pocket-ObjC-SDK

この問題を解決したところ無事審査も通り、ステータスが「Ready for Sale」になった。 3度のレビュー待ちがそれぞれ8日、10日、10日という感じだったので、計1ヶ月くらいレビュー待ってたことになる。。 個人の趣味で作ってるアプリだから良いんだけど、ビジネスでやってるアプリで同じようなこと起きたら結構な損失ですね😓 しっかり準備してレビューに臨むべきだった。

Pocketログインの修正

上記のログイン部分の修正部分のメモ。 ログインでSafariに飛んでしまうのを無理やり修正する。

UIApplicationクラスを継承したクラスを作成して、openURLメソッドをオーバーライド。 getpocket.comを開こうとした時のみ、NSNotificationCenterを利用してアプリ内で通知を送信する。

class CustomUIApplication < UIApplication
  def openURL(url)
    if !url.host.nil? && url.host.isEqualToString("getpocket.com")
      notificationCenter = NSNotificationCenter.defaultCenter
      notificationCenter.postNotificationName("PokebuOpenPocketAuthNotification", object: url)
      return
    end

    super
  end
end

Pocketログインボタンを表示するコントローラでは、上の通知のオブザーバーを追加し、通知が来た時に実行されるメソッドを作成。 SVWebViewControllerを利用して、Webビューのモーダルを表示。

class IntroViewController < UIViewController
  def viewDidAppear(animated)
    ...
    
    # NotificationCenterにオブザーバー追加
    notificationCenter = NSNotificationCenter.defaultCenter
    notificationCenter.addObserver(self,
      selector: 'openPocketAuth:',
      name:     "PokebuOpenPocketAuthNotification",
      object:   nil
    )
  end
  
  # 通知が来たら
  def openPocketAuth(notification)
    webViewController = SVWebViewController.alloc.initWithAddress(notification.object.absoluteString)
    @pocketAuthNaviController = UINavigationController.alloc.initWithRootViewController(webViewController)
    self.presentViewController(@pocketAuthNaviController, animated: true, completion: nil)
  end
end

オーバーライドしてしまったので、Rakefileinfo.plistを変更。

# Rakefile

Motion::Project::App.setup do |app|
  ...
  
  app.info_plist['NSPrincipalClass'] = 'CustomUIApplication'
  
  ...
end

これでアプリ内でログイン出来るようになった。

RubyMotionについて

やっぱりRubyで書けるのは心地よくて、RubyMotion好きである。 CocoaPodsのライブラリも普通に使えるし、 iTunes ConnectへのアップロードなんかもHipByteがライブラリ出してて簡単に出来た。 気軽に作れて非常に良い。

一方で、Swiftがスタンダードになっていく時流の中で敢えて使い続ける理由も無いかなとは思っていて、 今後個人で別のアプリを作ろうとなったときにどうするかは結構悩む、Objective-Cほど抵抗もないし。。 Androidアプリも書けちゃうし、魅力的ではあるのだが。

今回に限って言えば、Cocoa touchの部分の習得(UIKitフレームワークとか)に集中できたので、RubyMotionで良かったかなと思っている。 慣れてない別の言語で書き始めると、その言語の記法が分かんなくて詰まったりするので。。

おわり

そんなわけでアプリを作ってみての簡単な振り返り的なやつでした。 超基礎的なUIを使っただけだし、iOSマスターしたなんて口が裂けても言えないけど、 アプリの作成・審査・リリースまでの流れを自分で体験できたのは非常に良かった。

会社の技術陣のポートフォリオも例えば1年前と比べると少しずつ変わっていて(増えていて)、 ようやくネイティブアプリの分野が入ってきて、遅まきながらモバイル対応が始まった感がある。 Swift書けて僕より全然iOSに詳しい同期もいるし、1年目ながらアプリデザインできる子もいる。 自分のポジションとしてモバイル方面にどこまでコミットしていくべきなのか定めてないが、 機会があるのに何もできないのも嫌なので今後も触れていきたいところではある。 (会社でやるなら間違いなくSwiftになるので、要習得)

アプリのLP作る気力が全く沸かなくて困る。それでは今回はこのへんで。