ROADTO みちログ

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

GeoFenceとCoreMotionを組み合わせたバックグラウンド常駐監視の一案

仕事へのパッションが抑えられません。

ジオフェンシングとモーションセンサーを使って
バックグラウンドやロック状態でも何かをしたいときの一案。

ジオフェンシングって知ってますか?

そうだね、プロテインだね。

ではEnjoy ジオフェンシングとモーションセンサー!

やりたいこと

ある領域内にいるうちは定期的に何かしたい。

何かのトリガーでバックグラウンドでアプリを起動させても動くのって10秒ほど。
がんばって延長させても最長10分弱。

そうじゃなくて定期的に何かしたい。

やることの要約

  • 指定領域内に入ったらモーションセンサー開始
  • モーションセンサーで歩くたびに何かする
  • 指定領域内は継続
  • バックグラウンドでもロック時も動作開始、継続
  • 指定領域から出たらモーションセンサー停止

前提

  • Xcode6.3.1
  • 検証機はiPhone6plus iOS8.3。
  • AppStoreに申請したことはない。
  • SwiftじゃないよObjective-Cです。

「・・・」のところは本筋から外れるので間引いています。
気になる方はサンプルコードからどうぞ。
サンプルコード

実装のまえに

プロテイ、、プロジェクトの設定をします。

位置情報「常に使用」を有効にします。
* Info.plistにNSLocationAlwaysUsageDescriptionを追加 f:id:hitonomichi:20150529192716p:plain バックグラウンドで動かす設定をします。
* TARGETS - Capabilities - Background Modes をON
* Location updatesにチェックをつける
f:id:hitonomichi:20150529192733p:plain

やっと実装

まずはインポート。

余談ですがframeworkに追加しなくてよくなったのね。
framework追加なしでエラーになりません。

#import <CoreLocation/CoreLocation.h>
#import <CoreMotion/CoreMotion.h>

CLLocationManager初期化と監視領域の指定。

CLLocationCoordinate2DMakeで指定した緯度軽度を中心に、
CLLocationDistanceで指定した領域を監視します。

//CLLocationManager初期化
self.locationManager = [[CLLocationManager alloc] init];
・・・
self.locationManager.delegate = self;

//Region初期化
CLLocationCoordinate2D coordinate 
    = CLLocationCoordinate2DMake(37.324540, -122.041241);//アメリカ(クパチーノ)
CLLocationDistance radiusOnMeter = 100.0;//範囲指定
self.geoRegion = [[CLCircularRegion alloc] initWithCenter:coordinate
                                                   radius:radiusOnMeter
                                               identifier:@"jp.roadto.ROADTO-Geo"];

//位置情報の許可状況に合わせて動作開始
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
    // iOS8
    switch ([CLLocationManager authorizationStatus]) {
        case kCLAuthorizationStatusNotDetermined:
            NSLog(@"位置情報の許可が未設定なのでユーザに確認する");
            [self.locationManager requestAlwaysAuthorization];
            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            NSLog(@"「常に許可」されている");
            break;
            ・・・
    }
} else {
    // iOS7以下
    [self.locationManager startUpdatingLocation];
}

続きましてCLLocationManagerDelegateメソッドたち

requestStateForRegionで監視が始まったときとか
requestAlwaysAuthorizationの位置情報使用確認後とかに通知されます。

領域内に入ったときにモーションセンサーをONにし、
領域外になったときにモーションセンサーをOFFにします。

説明はコメントにて。

#pragma mark - CLLocationManagerDelegate
// CLLocationManager初期化時または
// アプリの位置情報の許可状態ステータスが変更されたときに通知される
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:
            break;
        case kCLAuthorizationStatusAuthorizedAlways:
            NSLog(@"「常に許可」");
            // 領域監視スタート
            [self.locationManager startMonitoringForRegion:self.geoRegion];
            break;
            ・・・
    }
}

//領域監視がスタートしたときに通知
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region {
    //現在の領域状態を確認。
    //「- locationManager:didDetermineState:forRegion:」が呼ばれます。
    [self.locationManager requestStateForRegion:region];
}

//領域内に入ったときに通知
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {
    NSLog(@"領域内になったよ");
    
    //モーションセンサー 開始 内容は次の章で説明。
    [self startMotionActivity];
}

//領域の状態について通知。状態が変わるたびに呼び出される。
- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region {
    switch (state) {
        case CLRegionStateInside:
            NSLog(@"領域内");
            //モーションセンサー 開始 内容は次の章で説明。
            [self startMotionActivity];
            break;
            ・・・
    }
}

//領域から出たことを通知
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {
    NSLog(@"領域外になったよ");
    
    //モーションセンサー 停止
    [self stopMotionActivity];
}

あとはモーションセンサー

CMMotionActivityManagerを使ってモーションを取ります。
今回は歩いているか否かを使っていますが、他にもいろんな状態をとれます。
「//do something」でしたい何かの処理を書きます。

#pragma mark - モーションセンサー
//モーションセンサー 初期化
- (CMMotionActivityManager *)getActivityManager {
    if (!self.motionActivityManager) {
        self.motionActivityManager = [[CMMotionActivityManager alloc] init];
    }
    return self.motionActivityManager;
}

//モーションセンサー 開始
- (void)startMotionActivity {
    NSLog(@"モーションセンサー 開始");
    
    //iOS7,8ともに必要
    [self.locationManager startUpdatingLocation];    //←キモ。iOS7,8ともに必要です。
    
    if([CMMotionActivityManager isActivityAvailable]){
        NSOperationQueue *queue = [NSOperationQueue mainQueue];
        CMMotionActivityManager *motionActivityManager = [self getActivityManager];
        [motionActivityManager startActivityUpdatesToQueue:queue withHandler:^(CMMotionActivity *motionActivity){
            
            //do something

            NSString *log = [NSString stringWithFormat:@"motion %@", motionActivity.walking ? @"そうだね。プロテインだね。" : @"んーんーんー。"];
            NSLog(log);
            ・・・
        }];
    }
}

//モーションセンサー 停止
- (void)stopMotionActivity {
    NSLog(@"モーションセンサー 停止");
    CMMotionActivityManager *motionActivityManagerUpdate = [self getActivityManager];
    [motionActivityManagerUpdate stopActivityUpdates];
}

テストに出ます

「←キモ」のところ。
startMotionActivity内で「-locationManager startUpdatingLocation」を呼んでいます。
これ自体は位置情報の更新監視をスタートさせるものですが
なぜかこれを書くとモーションセンサーもバックグラウンドで動いてくれます。

バックグラウンドでもロック状態でも起動するし、
フォアグラウンドで起動して、バックグラウンドやロック状態になっても動き続けます。

尚、「M7」モーションセンサーはiPhone5sから搭載なので、
iPhone5以前は使えません。

結果

サンプルコードを起動させます。
サンプルコードでは画面に出力させています。

歩いているかどうかを判定しています。
歩いてると出てますね。「そうだね。プロテインだね。」
f:id:hitonomichi:20150529193201p:plain

バックグラウンドでも動いていますね。「そうだね。プロテインだね。」
f:id:hitonomichi:20150529193317p:plain

以上です。

エヴィバディパッション!

Road to Passbookの作成

Passbookを作ってみる機会があって色々調べたので残しておきましょう。
ではEnjoy Passboooooooooook!

前提

  • MacYosemite
  • 検証機はiPhone6plus iOS8.2。
  • iOS Developer Program に登録していること。
  • 自動更新とかサーバ絡んだことは考慮しない。

素材を集める

証明書を作成

「キーチェーンアクセス」ー「証明書アシスタント」ー「認証局に証明書を要求」
「CertificateSigningRequest.certSigningRequest」ができました。
あとで使います。

Pass Type IDsを作成

デブセンでPass Type IDsを作成します。
証明書(さっき作った.certSigningRequest)を使用します。
できたらDownloadします。
ダブルクリックでキーチェーンに保管します。

テンプレートをゲットだぜ

Passbookのテンプレートを取得します。
ここから。Passbook Support Materials
「Passbook Materials」てリンクからダウンロード。
落ちてきたpassbook_materials.dmgを開く。

必要なやつだけ別に置いてみたら分かりやすいんじゃね?

任意の場所にフォルダを作成。今回は「PassSample」とします。
「PassSample」にサンプルjsonファイルと必要素材のどれかを置きます。
今回は「Generic.raw」を使用します。
signpassのプロジェクトをXcodeでビルドし作成されたsignpassを「PassSample」フォルダに移動に置きます。
f:id:hitonomichi:20150328155047p:plain
こんな感じ。

Passbookの中に具を詰めます

pass.jsonを編集します。

まず、必要な情報があるのでキーチェーンアクセスから証明書を見てみます。
作成して保存した証明書を右クリックから「情報を見る」で開きます。 f:id:hitonomichi:20150328155028p:plain
詳細な情報を開くと、あったあった。

これらをpass.jsonに設定します。

  • passTypeIdentifierにPass Type IDを指定
    例)"pass.com.example.PassbookSample"
  • teamIdentifierに部署を指定。10桁の英数字文字列です。
  • organizationNameに組織を指定。

その他必要な項目を設定します。
ここを参考に。
Pass Design and Creation

オーブンに入れて出来上がりを待ちます

ターミナル起動。
「PassSample」ディレクトリに移動。
実行。
./signpass -p Generic.raw

Generic.pkpassができました!
ダブルクリックでプレビューできます。
作成手順は以上です!

アレンジで自分だけのPassbookを。

去年のWWDCで現地のディベロッパーは名刺をPassbookで持ってるって耳にしたので、
試しにひとのみちPassbook名刺をつくりました。
ひとのみちPassbook名刺
iPhoneだとPassbookアプリに入るよ。
え?いらない?ですよね。いらない人は燃えるゴミの日にだすか、かたつむりにあげてください。

別腹

余談ですが。 PassbookはiBeaconに反応してロック画面に表示しますが、
表示対象のPassbook複数あったらどうなるか。
たぶん並んで表示されるんやろーなーと思ってたら、、なんと! f:id:hitonomichi:20150328162438j:plain
思ってた通り並んで表示されました。

ちなみに、passTypeIdentifierが違えば別モノとして表示、
passTypeIdentifierが同じでserialNumberが違うと同じpassTypeIdentifierのうちどれか一つが表示されました。

食後に

PassbookはiBeaconや緯度経度に連動するし、
AppleWatchにも搭載されるし、
あんまり流行っていないけど、使い道はあると思ってるんですけどね。

自動更新とかサーバ絡んだことはまたそのうち研究します。

iBeaconとPassbookのサンプルを作ったよ。

iBeaconとPassbookのサンプル作りました。 サンプルコードとか技術的な話はないです。ないんです。

ビーコンとは最近流行ってるIoTの切り込み隊長で、 電波を発信してモバイル端末に訴えかける仕組みです。

小売店や映画館とか、割と事例が出てきてます。

はい。 こんな感じです。

作ったサンプルですが、下の写真の黒い四角いのがビーコンです。 一個1000円で電池で動きます。

f:id:hitonomichi:20150303012331j:plain

空想上の街イベントアプリを作りました。

食とバンド、アートが街のいろんなところで楽しませてくれます。

例えば、ハンバーガーショップに近づくとアプリがビーコンに反応します。 ピロンとアラートが表示されますねー。

この例ではクーポン¥300,000OFFをゲットです。
f:id:hitonomichi:20150303013824g:plain

店側からしたら、なかなかアピールする手段がない中、 こちらから訴えかける一つの仕組みとして有効ですね。

あと、Passbookも一度iPhoneに取り込めばビーコンに反応して、 ロック画面に出てきます。

こちらも合わせてアピールの道具になりそうですね。

入力欄付きUIAlertControllerサンプル

iOS8から登場したアラートコントローラー「UIAlertController」のメモ。
パスワード入力欄付き。

前提

selfはViewControllerね。

ソース
UIAlertController *alert
    = [UIAlertController alertControllerWithTitle:@"タイトル"
                                          message:@"メッセージ"
                                   preferredStyle:UIAlertControllerStyleAlert];

//入力欄(UITextField)付きを設定
[alert addTextFieldWithConfigurationHandler:^(UITextField *textField) {
    //入力欄に薄くでるアレ
    textField.placeholder = @"パスワードを入力";
    //マスク(*表示)
    textField.secureTextEntry = YES;
}];

//キャンセルボタンと処理
UIAlertAction *actionCancel 
    = [UIAlertAction actionWithTitle:@"キャンセル"
                               style:UIAlertActionStyleCancel
                             handler:nil];
[alert addAction:actionCancel];

//OKボタンと処理
UIAlertAction *actionOK 
    = [UIAlertAction actionWithTitle:@"OK"  
                               style:UIAlertActionStyleDefault  
                             handler:^(UIAlertAction *action) {
                            
                                 //OKタップ時の処理

                                //alert.textFieldsにUITextFieldが入っている
                                UITextField *textField = alert.textFields.firstObject;
                                if ([textField.text isEqualToString:@"0000"]) {
                                    NSLog(@"パスワードOK");
                                }
                             }];
[alert addAction:actionOK];

//表示
[self presentViewController:alert animated:YES completion:nil];

f:id:hitonomichi:20150203000206p:plain

アクションボタンのスタイルはUIAlertActionStyleで指定。

2014年に通った道と2015年の道しるべ。

関西・大阪在住のフリーランスアプリ開発者です。 新年明けたということで(1月中なのでセーフ)去年の総括をします。
(まじめに。)

トピック

  • 2014年に通った道
    • WWDC2014に参加
    • 知り合いのアプリスペシャリストな会社に常駐
    • WebシステムのiPadアプリ移植
    • AlermWeatherリリース
    • 某機関の某診断アプリ
    • 某機関の某診断アプリ2
    • 営業さん用 社内PDF・動画・画像専用ビューアアプリ
    • アメホリバルアプリリリース
    • くまプレの開発支援
  • 2015年の道しるべ

2014年に通った道

フリーランス半会社員な感じでした。
生活リズムは、昼は仕事に出て夜と土日は自宅でという感じ。
ではいってみましょう♪
順不同です。

WWDC2014に参加

アメリカ本土初上陸でした。世界は思ってたより狭くて近かったです。
得たものをよく聞かれるけど半年たって今考えると大きく3つ。
- 最新キーワードにアンテナ張るようになった。
- 日本人ディペロッパーとの出会い&再会で単純に嬉しいしそこからのインプットが増えた。
- 上2つの相乗効果で意識の向上で視野も広くなった。
2015も行きたいと。私ははい。思ってます。
壁は抽選と家庭内稟議・・。

アプリスペシャリストな会社に常駐

これまでSIerへの常駐が多かった私ですが初めて知り合いのアプリ開発会社*1に常駐しました。
いろいろカルチャーショックを受けましたね。
知識やノウハウもさることながら、スピード。
意思決定のスピード、求められる開発スピード、スピードに関してが最も大きなインパクトが有りました。
逆にスピードなしではアプリの世界では生きて行けないのかも。
身にしみる思いでした。
ここではあの有名な○○の○○アプリやみんな知ってる○○の○○アプリを○○させて頂きました。*2
そういえば久しぶりにJavaもやりましたね。

WebシステムのiPadアプリ移植

Enterprise案件。
既存のWebシステムをiPadで使うためのアプリに移植。
JaveScriptをフックしてゴニョゴニョとか。

AlarmWeatherリリース

久しぶりのROADTOブランドのアプリ。
目覚ましと天気予報とツイッター投稿を速攻でするオレ得アプリ!
OpenWeatherMapのAPIを使ってます。

某機関の某診断アプリ その1

受託案件。
内容は内緒。
ViewからPDF作るのに苦戦。

某機関の某診断アプリ その2

受託案件。
内容は内緒。

営業さん用 社内ファイル専用ビューアアプリ

Enterprise案件。
外部に出したくないファイルを安全に見るためのiPadアプリ。
営業が持って回る社内PDF・動画・画像の専用ビューアアプリです。
DBとファイルの暗号化とか。

アメホリバルアプリリリース

共同開発のStoreアプリ。
大阪ミナミのアメ村/堀江のイベント、「アメホリバル®」の公式アプリです。
@tinpayさんと一緒につくりました。 ミナミの発展に寄与できれば幸いですね。
今年もバージョンアップする予定です。
ポコポコポコ〜

f:id:hitonomichi:20150123114755g:plain

アメホリバルについてはこちら。
そして@tinpayさんの記事。

アメホリバル - 関西最大級のバルイベント

アメホリバル - 関西最大級のバルイベント

  • Risa Umeda
  • フード/ドリンク
  • 無料

くまプレの開発支援

@EijiShibutani さんの「【本格RPG】くまのプレイといにしえの大戦記」の開発支援をしました。
DBでのデータ管理とサーバ側、サーバ接続部分を支援。
MBaasを使って初めて構築。
Promiseの概念もちょっと勉強できました。
ゲームの世界も面白そうです。

感想。

我ながら昼夜問わず働きました。
過去最高の労働時間でした。
それが良いか悪いかは別にして。。
ただ、
だんだん自分の思い描く仕事内容や仕事環境に近づきつつあるなと。
以前はまりかけていた負のスパイラル*3からは抜け出せつつあるはず。
そして、たまたまかもしれないけど需要があってよかったね!(ほっ)とも思います。

2015年の道しるべ

今年はこんなことを考えています。

受託案件中心にしたい。

常駐で拘束時間が多かったので、今年はライフワークバランスを考えるために受託案件を多くしたいです。
受託案件が楽というわけでは決してないです。
責任を持って自分を律して時間を有効に使う意味を含んでいます。
コワーキングとかも試してみてもいいかと。

iPhone+何か

iPhoneiPadの中で閉じる世界から飛び出して、
例えばiBeacon、BLE、ウェアラブルなやつなんかをやりたいです。

もう少しAppStoreとかかわりたい。

基本ツール系で。
ゲームの開発支援とかもいいかな。
ROADTOブランドのStoreアプリも作りたい。
ま、ここは優先度は低めです。

おわりに

何事もバランスなので、土台作りしながら先鋭的なところもやっていきたいと思っています。
がんばる!という次元ではなく、ちゃーんと戦略的に。

これ以上、海パンとゴーグルできゃべつ畑の真ん中にいたら凍えるのでこのへんで。
どうぞ皆様、今年もよろしくお願いいたします。

*1:私がそう思っているだけです。中の人の思いはそうではないかもしれません。

*2:言いたいけど言えなーい。

*3:私が見てきた中小企業SEの道のことについての持論。

iPhoneのスクリーンをgifに。

iPhoneのスクリーンをgifにしたいほどの昼下がりってありますよね。

手順メモ。
自己責任で。

前提

  • MacYosemite
  • FFmpegをインストールしておく。
    $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    $ brew install ffmpeg

手順

  1. MaciPhoneを接続
  2. QuickTimePlayer起動
  3. ファイル ー 新規ムービー収録
  4. iPhone操作で収録
  5. ファイル保存
  6. ターミナル起動
  7. ディレクトリ移動
  8. コマンドでmovをgifに変換

$ ffmpeg -i input.mov output.gif

サイズ指定となんだか遅かったのでオプション付けていい感じに。

$ ffmpeg -i input.mov -s 375x667 -an -r 15 -pix_fmt rgb24 -f gif output.gif

できあがり

f:id:hitonomichi:20150123114755g:plain

サイズやfpsもオプションで変えれるみたい。

アプリ内に保存したファイルをiTunesのファイル共有に表示する

iTunesのファイル共有に表示する手順。

アプリで作ったファイルをiTunesから見たいときの実装メモ。

  1. TARGETS-Infoに設定します。
  2. +ボタンで追加
  3. 「UIFileSharingEnabled」を入力
  4. 自動で「Application supports iTunes file sharing」になる
  5. ValueをYESに変更

f:id:hitonomichi:20150118074706p:plain

DocumentsフォルダがiTunesから見えるようになります。

参考:InfoPlistのKeyのリファレンス

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

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