ROADTO みちログ

ひとのみちのブログ。大阪でiOSアプリの道を歩くフリーランス。

フリーランスアプリ開発者が2016年7月〜9月に通った道

f:id:hitonomichi:20160104004403p:plain
関西・大阪在住、フリーランスアプリ開発者の私@hitonomichi2016年7月〜9月の活動まとめです。
前回の活動まとめから3ヶ月経ったので自分自身での振り返りがてら、
3ヶ月間の総括をします。

お仕事のお問い合わせはこちらからお願いいたします。
f:id:hitonomichi:20160410090308p:plainROADTO Webページ

トピック

2016年7月〜9月に通った道

  1. シフト管理サービス
  2. 受付アプリ
  3. BLE連携アプリ
  4. アメホリバルアプリ
  5. MorningJamで発表

それではいってみましょう(σ・∀・)σ
順不同です。

シフト管理サービス

WebとAppStore向けアプリの共同開発案件。
不定期シフト管理サービスです。
人を不定期に不特定の場所へ派遣する業務の連絡を効率化します。

現在開発中でα版程度が出来上がってきたところ。

iOSの開発と、その他開発に関わるディレクションをしています。
スケジュール管理、アーキテクチャ選定、要求仕様作成、設計、iOS実装を担当。 今後は営業のことも考えて、運用も考えていかないといけない。

iOSアプリは、通信部分はAPIKit+Himotoki、データベースはRealmです。

Web画面とサーバアプリはチームメンバーに任せています。
一人じゃないって心強い。

苦労しながら楽しんでやってます。
引き続きがんばって具現化します。

受付アプリ

AppStore向けアプリの受託案件。

病院の受付アプリ。
アプリでQRコードを読み込んで受付。
その後いろいろやっていい感じに受付業務を効率化します。

リアルな現場で役に立つ、個人的に好きな仕事です。

BLE連携アプリ

AppStore向けアプリの受託案件。

BLEガジェット同士を連動したり、
BLEガジェットとスマホならではの機能を連動したりします。
BLEで繋がるガジェットで現状の家電を操作できるのものがあるので、
Web連携してリモートでおうちハックもできたら便利になるかも。

これもリアルと繋がっているので、楽しい仕事仕事です。

アメホリバルアプリ

f:id:hitonomichi:20161003110709p:plain
共同開発のAppStoreアプリ。@tinpayさんと一緒につくってます。

毎年秋に開催される、大阪ミナミのアメ村/堀江のイベント、「アメホリバル®」の公式アプリです。

今年も去年に引き続きiBeacon機能を搭載。
デザインも2016年バージョンに変更。
参加店にiBeaconを置いてもらって、近くのお店を教えてくれる機能を導入があります。

今年も行くよアメホリバル!

amehoribar.com

MorningJamで発表

f:id:hitonomichi:20161003111037p:plain
MorningJamとは入居しているシェアオフィスでやってる朝の勉強会の事です。
このシェアオフィスはスタートアップ企業が集まっていて、月2回、それぞれのビジネスモデルを発表して質疑応答します。
今回それに始めて発表しました。

ビジネスモデルや展開について指摘をもらって参考(殴られた(論理)に近い)になりました。
これまで人前でビジネスモデルを話す機会なんてなかったので、スライドの作成やストーリー作成の勉強にもなりました。

総括

前回の総括でのプランからどうだったか。

サービスの立ち上げは?

大きな問題もなく、粛々と作るフェーズでした。
WebとiOSの連携もいい感じになってきたと思います。

引き続き受託は?

半分受託は相変わらず。
個人的に面白い仕事を頂けてるので、大変ありがたいです。

2016年10月〜12月への道しるべ

これからについて。

サービスの立ち上げシフト管理サービスの話です。

メインの仕事として続きます。
iOSアプリが終わったらAndroid版を後追いで作る予定です。
営業も始まるのでそちらも。
チームでパッション持ってやっていきたいです。

引き続き受託

半分は受託をする見込みです。
ありがたいことに既にいくつかお話は頂いています。
価値のあるものにしたいですね。
あとiPhone+何かの仕事も。

おわりに

シェアオフィスに入居して4ヶ月経ちました。
常駐してた頃、通勤の時間は無駄だとずっと思っていましたが、今は有効に使えています。
外に出て歩いて空気を感じるのが私は合ってそうです。

仕事の方は、見積もり依頼もちょこちょこ頂いていて、
最近はチームで提案することが多いです。
デザイン、Web、AndroidiOS、まるっとチームでお請けするので、そんな案件もご相談頂けたらと思います。

リオオリンピックがあったり千代の富士が亡くなったりお気持ち表明があったりで
世間は動いていますが、しっかり地に足を付けて頑張ろうと思います。

皆様どうぞ今秋もよろしくお願いいたします。

お仕事のお問い合わせはこちらからお願いします。
f:id:hitonomichi:20160410090308p:plainROADTO Webページ

過去の道

「新経済連盟 KANSAI SUMMIT 2016」に参加してみました。

f:id:hitonomichi:20160906115703j:plain

ちょっと背伸びをして「新経済連盟 KANSAI SUMMIT 2016」に参加しました。

jane.or.jp 自分に響いたメモを残しておきます。
誰の発言かは書いていませんが悪しからず。

オープニング

新経済連盟はこの3つの促進を掲げてる民間の経済団体です。

つまりは、民間が集まって大きな声にして政治に提言していこうということです。

今、政策提案をしている3つがあります。

  • インテリジェント・ハブ化構想
  • スマートネイション
  • 超観光立国

ここに資料があります。「Japan Ahead」

jane.or.jp

セッション1 競争と共創 〜FinTechの現場から〜

freee株式会社 佐々木社長
コイニー株式会社 佐俣社長
株式会社マネーフォワード 辻社長

Q.FinTechで生活をする上でどう変わるか、どうなるか

  • 一日中入力業務している社員がいた。何度も同じ入力があった。小さいビジネスでは未だに紙が多い。これはIT化できないはずはない。
  • AmazonPrimeNowのように、今はものよりもお金のほうがが動くのが遅い。
  • 人工知能を使って効率化する。
  • 商売でやるべきことだけできるようにしたい。
  • 当初のイヤフォンジャック型のカードリーダーは日本人は「なんか怖い」らしく、機械っぽい形になって爆発的に伸びた。
  • インバウンド向けにキャッシュレスをすすめる。
  • 経産省に「FinTechな生活」を提言しました。

    【提言】経済産業省の会合で、FinTech推進のための政策提言を発表しました

jane.or.jp

Q.注目しているものは?

  • 中国発のWechatに注目。WechatはLINEみたいなもの。中国はすすんでて交通、タクシー、飲食、税金など全部まかなえる。
  • Uberがやっぱすごい。
  • ケニアがモバイル主導になっていて、モバイルバンキングが進んでいる。

Q.日本にしかないものはないか?

  • おサイフケータイが10年前からある。本来海外にもっていくべき
  • 日本の個人向けアプリの領域は質が高いしチャンスがあるのではないか。

セッション2「KANSAIの底力と未来」

ジェイコムホールディングス株式会社 岡本社長
akippa株式会社 金谷社長
株式会社フリープラス 須田社長
株式会社ロックオン 岩田社長

フリープラスはインバウンドに特化した会社。 リアルどまんなか。 新今宮にホテルを作った。これこそがイノベーション

ロックオンはマーケティングロボットカンパニー。 オムライス屋を乗っ取って、いや譲り受けて経営者スタート!

Q.起業を何故考えたのか

  • 優秀な人間をあつめて会社を作った。これを残せたら素晴らしいと思って。
  • 高校卒業後サッカーコーチしてた。が、かせげない。PL花火のときサンガリアのジュースを買って売ってた。雨降ってきたら傘買って売ってた。自然と商売していたし、自分が商売やったら凄いことになるんじゃないかと思っていた。

Q.関西が本社である事のメリット・デメリットは?

  • メリットは坪単価安い。会社環境を整備するにに安い。
  • メリットは採用。そろそろ関西に戻りたい人がいて、東京のメガベンチャーから人材がきてくれる。
  • デメリットは情報が少ないこと。身近なところで上場するひとがいない。東京へ行ってしまう。起業家が神のように思われる。
  • グローバルの視点で見ると、東京だからってめちゃくちゃ評価されている企業なんてひとつもない。日本ブランドでいうと京都や大阪も魅力がある。
  • メリットは資金調達元は東京の会社がおおいけど同じように見てくれる。実は大阪にいると少ないから目立つ。

セッション3 新しい社会のインフラを創造する 〜起業から現在までの軌跡〜

f:id:hitonomichi:20160907101538p:plain

楽天株式会社 三木谷社長
株式会社サイバーエージェント 藤田社長
株式会社クラウドワークス 吉田社長

  • 図太さが必要。イーロン・マスクと二人でランチした。イーロンはふてぶてしい。自動運転が事故っても動じない。
  • いまろくな分野がない。VRも怪しい。学生がアプリを作って起業というものが難しくなっている。
  • とにかく集客しておけばあとからお金は付いてくるというのがいまは難しい。きちんとマネタイズできるものが良いと思う。
  • FinTich、IoT、シェアリングエコノミーは良いかもしれない。
  • シェアリングエコノミーや日本のコンテンツを海外に持っていくものや社会課題解決は興味ある。

最後に一言。

藤田社長:関西に期待している。でも東京で事足りちゃう。特徴がほしい。集積効果とか。やっぱり関西に行かないと、というものを出して欲しい。
三木谷社長:ITハブとして。大きな会社とスタートアップの間が空いてる。府県や市のバックアップも必要。

f:id:hitonomichi:20160907101521p:plain

感想

関西について考えてみました。
関西はポテンシャルがあると思ってるんですよ。
観光資源が豊富で、日本っぽさがたくさんあります。
実際インバウンドも多いしリピーターは東京より大阪の方が多い。
道頓堀のあたりなんて多いレベルじゃなくてほとんどアジア人です。
地震も台風も少ないですし。
梅田では北の方の開発「うめきた2期」が始まってます。
蛇足ですが、出来上がるまで暫定利用もするらしい。
うめきた2期区域の暫定利用を行う事業者を決定しました
健康産業と緑地にするらしいです。新しい駅もできます。
10年以内には概ね終わります。
そうなるとまた周辺も開発が進むはず。
人口が減っていくことが確実なわけだから、闇雲にビルを立てまくって人を詰め込むだけじゃなく、魅力ある都市になって欲しいです。
俺大阪生まれ大阪育ちやねん。ええやろ、とドヤ顔で住みたいわけです。

じゃあ自分はどうするのかというと、今やってる事業をちゃんと動かして経済活動することから。
地道だけどそこから。

個人事業主の自分はちょっと場違いであったかもしれませんが、いつもと違う視点を持つことも面白いし、気付きもたくさんありました。
懇親会では久しぶりと声かけてもらったり、はじめましてだけど知り合いの知り合いだったりで楽しかったです。
三木谷社長や藤田社長が2mの距離にいることもそうそうないことなので素直に嬉しかったです。
名刺交換はこんなんやってますって言えるようになってからにしました。
(写真は撮ってもらえばよかった。。)
また次の機会あれば参加したいと思います。

フリーランスは見つけてもらうのが全てのはじまり

関西・大阪で活動しているフリーランスアプリ開発者の
ひとのみち(@hitonomichi)です。

嬉しいことがあったので記しておきたいと思います。

検索ワード「フリーランス アプリ 大阪」で1位

記事投稿日現在、Google検索で「フリーランス アプリ 大阪」で1〜4位が私の記事になっています。
f:id:hitonomichi:20160810094702p:plain

これはついにGoogleが私を認めたといっても過言ではありません。
いえ、それは完全に過言ですすみませんすみません。

有名な経済学者のロドミッチ*1

3つのカテゴリーを掛けあわせてトップになれ

と言ってたのに感銘を受けてからそうなればいいなーと思っていましたが、ひとつ成果が出ました。

私は基本的に開発者なのでプッシュ型営業が出来ません。
プル型営業頼みです。
なので、検索流入はプル型営業のチャンネルとして大切なものだと思っています。

有名な経済学者のロドミッチ*2

見つけてもらう、存在を知ってもらうのが全てのはじまりだ

と言っていたのを身をもって感じています。

キーワードを関西に変えると3位(記事投稿日現在)になってしまうので、まだまだ小さい範囲ではありますが、ひとつ名前が出やすくなったことが喜ばしい件でした。

Discovered

結果につながらないと意味が無い

有名な経済学者のロドミッチ*3が提唱するフリーランス営業三原則、

  1. こんな店あるんだ。
  2. うまそう。食べてみたい。一回食べてみよ。
  3. うまかった。また来よう。

このサイクルを大事にしていきたいですね。

まあ検索で特定のワードで上位だーやったーと言ってても意味がないので、

  • 今のクライアントから信頼を得る。
  • 依頼したくなるような実績を積む。

といった目前の道の一歩をまずは大事にしていこうと思います。

10kmたまごも一歩から。

お仕事のお問い合わせはこちらからお願い致します。
f:id:hitonomichi:20160410090308p:plainROADTO Webページ

実績はこちら

hitonomichi.hatenablog.com

*1:ロドミッチなんて人はいません。

*2:ロドミッチなんて人はいませんって。

*3:だからロドミッチなんて人はいませんってば。

フリーランスアプリ開発者が2016年4月〜6月に通った道

f:id:hitonomichi:20160104004403p:plain
関西・大阪在住、フリーランスアプリ開発者の私@hitonomichi2016年4月〜6月の活動まとめです。
前回の活動まとめから3ヶ月経ったので自分自身での振り返りがてら、
3ヶ月間の総括をします。
長いので夏のバーゲンを調査し終わってから見てください。

お仕事のお問い合わせはこちらから。
f:id:hitonomichi:20160410090308p:plainROADTO Webページ

トピック

2016年4月〜6月に通った道

  1. 大阪ミナミのクーポンアプリ
  2. BLE連携アプリ
  3. スタッフコミュニケーションアプリ
  4. 研究機関の診断アプリ
  5. シェアオフィスに入居

それではいってみましょう(σ・∀・)σ
順不同です。

大阪ミナミのクーポンアプリ

AppStore向けアプリの受託案件。

大阪ミナミ地域の店舗集客アプリです。
外国人向けのクーポンアプリですね。
「i-Pon」

i-Pon jp

i-Pon jp

  • Navibird Inc.
  • Shopping
  • Free

iBeaconを搭載しています。
アプリを起動すると、近くにお店があれば自動的に知らせてくれます。
iBeacon(アイビーコン)とは発信機みたいなもので、近くにいるとお知らせしてくれます。
ブラッシュアップしていく予定です。

サーバ側プログラムとデザインはご提供頂いて、iOSアプリ開発を担当しました。
アプリだけ作って欲しいんだよねーという場合にはこういう形でも参画します!笑

BLE連携アプリ

AppStore向けアプリの受託案件。
Appleの審査もパスしていますがまだ世に出てはいません。

BLEガジェット同士を連動したり、
BLEガジェットとスマホならではの機能を連動したりします。
前述のiBeaconもそうですがBLEを扱うことが増えてきて嬉しい!
センサーやWebの情報も動作条件として組み込んでいく予定です。

用語からさっぱりだったBLEの知識もだいぶ付いたはずです。
いまだにわけわからない事もたくさんありますが・・。

スタッフコミュニケーションサービス

人材派遣業向けのスタッフ管理サービスです。
Webとスマホでスマートにコミュニケーションが出来ることを目指します。

現在開発中なのですが、iOSの開発と、その他開発に関わるディレクションをしています。
そんな言葉あるのか知らないけど、プレーイングディレクターとでも言いましょうか。

チームも、必要なポジションにプロがいるので心強いです。

その業界の中の人 → ノウハウ、経験、コネクション
開発者 → 具現化、価値化

必要な条件がいい感じに揃っているのでいい方向に行くんじゃないかと考えています。
まずは良い物を作るところから。

研究機関の診断アプリ

ブラッシュアップ案件。
ツール系のデータを集めるアプリなので小さな変更でも気を使います。
ドキドキ。
研究機関の診断アプリは継続してお仕事頂戴してる企業様からの案件です。
リピート頂きいつもありがとうございます!

シェアオフィスに入居

6月からシェアオフィスに入りました。
ベンチャーがたくさんいて頻繁に交流会やセミナーがあり、VCが来てお金の話をしていたり(私のところへではないよ)、刺激的な毎日です。
家で一人で作業して、奥さん子供とほのぼのしてた時とは全然違う(笑)

入居して一ヶ月なのでだいぶリズムも出てき、浮ついた感じもなくなってきたので、
最近は地に足を付けてもくもくと作業しています。

hitonomichi.hatenablog.com

総括

前回の総括でのプランからどうだったか。

受託案件中心にしたいと言っていたけど?

完全に受託のみに。
そして受託だけでなくサービス開発に発展してきました。
がんばります。

iPhone+何かをしたいと言っていたけど?

BLEガジェットの案件もやってAppleの審査も通ったのでまずまず。
実績としてもBLE案件やりました!といえる!  はず。

一人からの脱却と変化と言っていたけど?

Webのエンジニアと協業するようになりました。
会社じゃないし一人からの脱却までいかないけどまず一歩。
得意分野を活かして補完しあってお互い幸せというのを大事にしたいです。

2016年7月〜9月への道しるべ

これからについて。

サービスの立ち上げ

がっつりこれだけという訳にはいかないですが、メインの仕事として続きます。
まずはiOSアプリを良い物に作り上げます。
チームでやるのでパッション持ってやれそうです。

引き続き受託

半分は受託をする見込みです。
ありがたいことにいくつかお話は頂いています。
リピートして頂けるよう価値のあるものにしたいです。
あとiPhone+何かの仕事も。

おわりに

外に出るようになって、通勤とか面倒なところもありますが、
ちょっとした運動と外部刺激になって良いところもあります。
体調も朝5:30出発が習慣になっててすこぶる良いです。
仕事は開発するのみではない立場になったので、勉強しながらかつ自信持って進めていこうと思います。
WWDCがあったり日本の首都の偉い人が辞めますぞえって言ったりイギリスEU離脱があったり、 世間は騒がしいですが、しっかり地に足を付けて頑張ろうと思います。

皆様どうぞ今夏もよろしくお願いいたします。

お仕事のお問い合わせはこちらからお願いします。
f:id:hitonomichi:20160410090308p:plainROADTO Webページ

過去の道

  • 前回の活動まとめ

hitonomichi.hatenablog.com

WWDC2016セッションメモ「A Peek at 3D Touch」

WWDC2016セッションを見たメモです。
文中の画像やコードは公開情報から引用しています。
正確で詳しい内容をお求めの方は一次情報の確認をおすすめします。

A Peek at 3D Touch

A Peek at 3D Touch - WWDC 2016 - Videos - Apple Developer

ぐっ ぶっ ぴ のやつ。
こんなやつ。
f:id:hitonomichi:20160627085142p:plain
こんなやつとか。
f:id:hitonomichi:20160627085144p:plain

UIPreviewInteraction

f:id:hitonomichi:20160627085146p:plain 新しいやつ。
アプリ内の3D Touchに関する技術。
3D Touchが扱いやすくなりましたよ。

f:id:hitonomichi:20160627085147p:plain

UIPreviewInteractionDelegate

プロトコルに準拠します。

extension ChatDetailViewController :UIPreviewInteractionDelegate

UIPreviewInteraction

UIPreviewInteractionを生成します。

override func viewDidLoad() {
    super.viewDidLoad()
    replyPreviewInteraction = UIPreviewInteraction(view: view)
    replyPreviewInteraction.delegate = self
}

状態が二段階になってる。
開始〜プレビューの状態と、プレビュー〜コミットの状態。

ぐっと押して、プレビュー表示の状態。
f:id:hitonomichi:20160627085149p:plain ぐぐっと押して、コミット完了した状態。
f:id:hitonomichi:20160627085151p:plain

デリゲートメソッド

開始されたときのデリゲートメソッド。

previewInteractionShouldBegin() 

開始〜プレビューまでの状態の時に、
押す強さが更新されたら呼ばれるデリゲートメソッド。

func previewInteraction(_  previewInteraction: UIPreviewInteraction,
                        didUpdatePreviewTransition transitionProgress: CGFloat,
                        ended: Bool) {
    //ビューの更新処理
    updateForPreview(progress: transitionProgress)

    if ended {
        //プレビューの完了処理
        completePreview()
    }
}

プレビューがキャンセルされたら呼ばれるデリゲートメソッド。
指を離した時ですね。

func previewInteractionDidCancel(_ previewInteraction: UIPreviewInteraction) {
    //キャンセル処理
    UIView.animate(withDuration: 0.4) {
        self.updateForPreview(progress: 0)
        self.resetToInitialAppearance()
    } 
} 

プレビュー〜コミットまでの時に、
押す強さが更新されたら呼ばれるデリゲートメソッド。

func previewInteraction(_ previewInteraction: UIPreviewInteraction,
                        didUpdateCommitTransition transitionProgress: CGFloat,
                        ended: Bool) {
    //ビューの更新処理
    updateForCommit(progress: transitionProgress)

    if ended {
        //コミットの完了処理
        completeCommit()
    } 
}

f:id:hitonomichi:20160627085141p:plain

感想

この操作ができることをどうやってユーザーに知らせるかが課題ではある。
扱いやすくなったのではりきって3D Touchするぞー!

WWDC2016セッションメモシリーズはこちら

WWDC2016 カテゴリーの記事一覧 - ROADTO みちログ

WWDC2016セッションメモ「Advanced Notifications」

WWDC2016セッションを見たメモです。
文中の画像やコードは公開情報から引用しています。
正確で詳しい内容をお求めの方は一次情報の確認をおすすめします。

Advanced Notifications

Advanced Notifications - WWDC 2016 - Videos - Apple Developer

Media Attachments

ペイロード

{ 
    aps: { 
        alert: { ... }, 
        mutable-content: 1 
    } 
    my-attachment: "https://example.com/photo.jpg" 
} 

f:id:hitonomichi:20160624104746p:plain

// Adding an attachment to a user notification
public class NotificationService: UNNotificationServiceExtension {
    override public func didReceive(_ request: UNNotificationRequest,
                                      
                                      
                                      withContentHandler contentHandler: (UNNotificationContent) -> Void) {
        let fileURL = // ...
        let attachment = UNNotificationAttachment(identifier: "image",
                                                  url: fileURL,
                                                  options: nil)
        let content = request.content.mutableCopy as! UNMutableNotificationContent 
        content.attachments = [ attachment ]
        contentHandler(content)
    }
}

Media Attachments は、
Local notifications も Remote notifications も対応。
対応してるのは画像、音声、ビデオ。
時間やサイズに制限はあるよ。

Custom User Interface

通知内容を拡張できる。
ビューをカスタムできる。
通知アクションに応答する。

Notification Content Extension

「Notification Content」を選択。
f:id:hitonomichi:20160624104749p:plain

UNNotificationContentExtension を継承したUIViewControllerのサブクラスができる。

カスタムビュー

class NotificationViewController: UIViewController, UNNotificationContentExtension {

    @IBOutlet var eventTitle: UILabel!
    @IBOutlet var eventDate: UILabel!
    @IBOutlet var eventLocation: UILabel!
    @IBOutlet var eventMessage: UILabel!
    func didReceive(_ notification: UNNotification) {
        let content = notification.request.content
        eventTitle.text = content.title
        eventDate.text = content.subtitle
        eventMessage.text = content.body
        
        if let location = content.userInfo["location"] as? String {
            eventLocation.text = location
        }
    }
}

eventMessageの箇所
f:id:hitonomichi:20160624104751p:plain

eventMessageの箇所
f:id:hitonomichi:20160624104753p:plain

plistにいろいろ設定するらしい。 f:id:hitonomichi:20160624104755p:plain
f:id:hitonomichi:20160624104756p:plain
 こうなる。
f:id:hitonomichi:20160624104758p:plain
The Bash〜のところがUNNotificationExtensionInitialContentSizeRatioで措定されている。
Default content が非表示になってる。

メディアの追加

設定する。

// Notification Content Extension Attachments
class NotificationViewController: UIViewController, UNNotificationContentExtension {
    @IBOutlet var eventImage: UIImageView!
    func didReceive(_ notification: UNNotification) {
        let content = notification.request.content
        if let attachment = content.attachments.first {
            if attachment.url.startAccessingSecurityScopedResource() {
                eventImage.image = UIImage(contentsOfFile: attachment.url.path!)
                attachment.url.stopAccessingSecurityScopedResource()
            }
        }
    }
}

こうなる。
f:id:hitonomichi:20160624104804p:plain

アクションとレスポンス

// Intercepting notification action response
class NotificationViewController: UIViewController, UNNotificationContentExtension {
    func didReceive(_ response: UNNotificationResponse,
                      completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {
        server.postEventResponse(response.actionIdentifier) {
            if response.actionIdentifier == "accept" {
                eventResponse.text = "Going!"
                eventResponse.textColor = UIColor.green()
            } else if response.actionIdentifier == "decline" {
                eventResponse.text = "Not going :("
                eventResponse.textColor = UIColor.red()
            }
            
            // done(.dismiss)
            done(.dismissAndForwardAction) 
        }

        }
    }
}

こうなる。
f:id:hitonomichi:20160624104806p:plain

テキスト入力

UNNotificationCategoryをつくる。

// Text Input Action
private func makeEventExtensionCategory() -> UNNotificationCategory {
    let commentAction = UNTextInputNotificationAction(
        identifier: "comment",
        title: "Comment",
        options: [],
        textInputButtonTitle: "Send",
        textInputPlaceholder: "Type here...")
    return UNNotificationCategory(identifier: "event-invite",
                                  actions: [ acceptAction, declineAction, commentAction ],
}

こうなる。
f:id:hitonomichi:20160624104809p:plain

// Text input action response
class NotificationViewController: UIViewController, UNNotificationContentExtension {
    func didReceive(_ response: UNNotificationResponse,
                      completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {
        if let textResponse = response as? UNTextInputNotificationResponse {
            server.send(textResponse.userText) {
                done(.dismiss)
            }
        }
    }
}

アクセサリーのカスタム(?)

// Custom input accessory view
class NotificationViewController: UIViewController, UNNotificationContentExtension {
    override func canBecomeFirstResponder() -> Bool {
        return true
    }
    override var inputAccessoryView: UIView { get {
        return inputView
        }
    }
    func didReceive(_ response: UNNotificationResponse,
                      completionHandler done: (UNNotificationContentExtensionResponseOption) -> Void) {
    }
}

感想

出来ることが増えてここだけで機能完結できることもありそう。 がんばってリッチな通知するぞー!

WWDC2016セッションメモシリーズはこちら

WWDC2016 カテゴリーの記事一覧 - ROADTO みちログ

WWDC2016セッションメモ「Introduction to Notifications」

WWDC2016セッションを見たメモです。
文中の画像やコードは公開情報から引用しています。
正確で詳しい内容をお求めの方は一次情報の確認をおすすめします。

Introduction to Notifications

Introduction to Notifications - WWDC 2016 - Videos - Apple Developer

User Notifications Framework

f:id:hitonomichi:20160623100355p:plain

watchOS単独でLocalNotificationが使える

Registration

使うのにRegistration が必要。
ローカルもリモートも必要。

UNUserNotificationCenter.current().requestAuthorization([.alert, .sound, .badge])
    { (granted, error) in /* ... */}

ユーザ定義を設定する

UNUserNotificationCenter.current().getNotificationSettings { (settings) in /* ... */}

コンテンツ

TitleとSubtitleが追加された。
画像とかメディアも表示出来る。
f:id:hitonomichi:20160623100358p:plain

Local Notification

let content = UNMutableNotificationContent()
content.title = "Introduction to Notifications"
content.subtitle = "Session 707"
content.body = "Woah! These new notifications look amazing! Don’t you agree?"
content.badge = 1

Remote Notification

{
    "aps" : {
        "alert" : {
            "title" : "Introduction to Notifications",
            "subtitle" : "Session 707",
            "body" : "Woah! These new notifications look amazing! Don’t you agree?"
    },
    "badge" : 1 },
}

トリガー

f:id:hitonomichi:20160623100410p:plain

Time Interval

//2分後に発火
UNTimeIntervalNotificationTrigger(timeInterval: 120, 
                                  repeats: false)
//リピートするならrepeatsをtrueに。  

Calendar

//「明日朝8時に」「毎週月曜日の18時に」とか指定できる。
let dateComponents = DateComponents()
// dateComponentsに設定する
UNCalendarNotificationTrigger(dateMatching: dateComponents,
                              repeats: false)

Location

//「家についたら」「アモーレと思い出の場所に近づいたら」とか指定できる。
let region = CLRegion()
// ここでregionに設定する
UNLocationNotificationTrigger(region: region,
                              repeats: false)

どうやるのか

f:id:hitonomichi:20160623100412p:plain

// Notification Delivery Summary
import UserNotifications

//許可
UNUserNotificationCenter.current().requestAuthorization([.alert, .sound, .badge])
{ (granted, error) in // ... }

//コンテンツ指定
let content = UNMutableNotificationContent()
content.title = "Introduction to Notifications"
content.body = "Let's talk about notifications!"

//トリガー指定
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)

//リクエスト作成
let requestIdentifier = "sampleRequest"
let request = UNNotificationRequest(identifier: requestIdentifier,
                                    content: content,
                                    trigger: trigger)

//UNUserNotificationCenterに追加
UNUserNotificationCenter.current().add(request) { (error) in // ... }

ハンドリング

フォアグラウンドの時アプリ内表示ハンドリング

protocol UNUserNotificationCenterDelegate : NSObjectProtocol

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler handlerBlock: (UNNotificationPresentationOptions) -> Void) {
        // Roll banner and sound alert
        handlerBlock([.alert, .sound])
}

Notification Management

たくさんの通知うっとおしいよね。
最新の一件だけに更新できますよ。
f:id:hitonomichi:20160623100402p:plain

保留の通知を消す

保留の通知を消すこともできますよ。

// Pending Notification Removal
let gameStartIdentifier = "game1.start.identifier"
let gameStartRequest = UNNotificationRequest(identifier: gameStartIdentifier,
                                             content: content,
                                             trigger: startTrigger)

UNUserNotificationCenter.current().add(gameStartRequest) { (error) in // ... }

// Game was cancelled
UNUserNotificationCenter.current.current()
    .removePendingNotificationRequests(withIdentifiers: [gameStartIdentifier])

保留の通知を更新

保留の通知を更新することもできますよ。

// Pending Notification Update
let gameStartIdentifier = "game1.start.identifier"
let gameStartRequest = UNNotificationRequest(identifier: gameStartIdentifier,
                                             content: content,
                                             trigger: startTrigger)
    
UNUserNotificationCenter.current().add(gameStartRequest) { (error) in // ... }
// Game start time was updated
let updatedGameStartRequest = UNNotificationRequest(identifier: gameStartIdentifier,
                                                    content: content,
                                                    trigger: newStartTrigger)
UNUserNotificationCenter.current().add(updatedGameStartRequest) { (error) in // ... }

配信済みの通知を削除

// Delivered Notification Removal
let gameScoreIdentifier = "game1.score.identifier"
let gameScoreRequest = UNNotificationRequest(identifier: gameScoreIdentifier,
                                             content: scoreContent,
                                             trigger: trigger)
UNUserNotificationCenter.current().add(gameScoreRequest) { (error) in // ... }
// Wrong game score was published
UNUserNotificationCenter.current()
    .removeDeliveredNotifications(withIdentifiers: [gameScoreIdentifier])

配信済みの通知を更新

// Delivered Notification Update
let gameScoreIdentifier = "game1.score.identifier"
let gameScoreRequest = UNNotificationRequest(identifier: gameScoreIdentifier,
                                             content: scoreContent,
                                             trigger: trigger)
UNUserNotificationCenter.current().add(gameScoreRequest) { (error) in // ... }
// Score game was updated
let updateGameScoreRequest = UNNotificationRequest(identifier: gameScoreIdentifier,
                                                   content: newScoreContent,
                                                   trigger: newTrigger)
UNUserNotificationCenter.current().add(updateGameScoreRequest) { (error) in // ... }

アクション付き通知

  • ボタン付き
  • 返信とかのテキスト入力
  • iOSとwatchOSで使えます。

f:id:hitonomichi:20160623100405p:plain

let action = UNNotificationAction(identifier:"reply",title:"Reply",options:[])
let category = UNNotificationCategory(identifier: "message", actions: [action],
        minimalActions: [action], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])

非表示アクション

通知をスワイプで消せますよ。
optionsに設定します。

customDismissAction: UNNotificationCategoryOptions
let category = UNNotificationCategory(identifier: "message", actions: [action],
        minimalActions: [action], intentIdentifiers: [], options: [.customDismissAction])

感想

できること増えたね!

WWDC2016セッションメモシリーズはこちら

WWDC2016 カテゴリーの記事一覧 - ROADTO みちログ

自己紹介
メガネは売っていません
高浜 一道(たかはま かずみち)
大阪でiOSアプリの道を歩くフリーランス。
iPad・iPhoneとサーバを連携した、JSONやDBといったキーワードが出てくるツール系が多めです。
お仕事のご依頼やご連絡はこちらから。
お仕事ください!
Web : ROADTO
ML : k-takahama(a)roadto.jp

個人的なアカウントはこちら。
Tw : @hitonomichi
Fb : kazumichi.takahama