gitのcommitを変更しようとするとError detected while processing /home/XXX/.vimrc:と表示される

別に問題ないっちゃないんですが、やっぱりちょっと気持ち悪いので調べてみた。

git config --global core.editor 'vim -c "set fenc=utf-8"'

これでOK。

iOS8のNotification関係を調べてみた


What’s New in iOS Notifications

WWDC 2014のVideo Sessionを見てみる。 https://developer.apple.com/videos/wwdc/2014/

User Notification iOS7の説明

User Notificationsとは

  • Alert表示
  • Notification Centerに通知
  • スクリーンOFFの時に表示

User Notificationの実行

  • アプリからLocal Notificationを使う
  • APNsからRemote Notificationを使う
  • APNsからcontent-available: 1を指定してappを介して通信する

User Notifications iOS8

今回紹介するのは大きく以下の4つ
  • User Notifications
  • Notification Actions
  • Remote Notification
  • Location Notification

User Notifications

登録方法

UIRemoteNotificationTypeと同じようなイメージ
categoryという概念が追加されているが後ほど
UIUserNotificationType types = UIUserNotificationTypeBadge |
  UIUserNotificationTypeSound | UIUserNotificationTypeAlert;

UIUserNotificationSettings *mySettings = [UIUserNotificationSettings
  settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];

ユーザパーミッション

UIApplicationDelegateにCallbackメソッドがある
許可しない場合は、allowedTypes == UIUserNotificationTypeNoneとなる
 - (void)application:(UIApplication *)application
     didRegisterUserNotificationSettings:
    (UIUserNotificationSettings *)notificationSettings {

    // user has allowed receiving user notifications of the following types
    UIUserNotificationType allowedTypes = [notificationSettings types];
}

許可されたタイプの取得

- (void)getReadyForNotification {
  // ...
  // check to make sure we still need to show notification
  UIUserNotificationSettings *currentSettings = [[UIApplication
   sharedApplication] currentUserNotificationSettings];
  [self checkSettings:currentSettings];
}

Notification Action

iOS7ではそれぞれのNotificationに対して、スワイプで削除、タップで起動しかできなかった
iOS8ではスワイプして、複数のボタンを準備してアクションさせる事が可能




Actionの作成方法

ボタンのタイトルやバックグランド、ロック解除前でも可能かどうかを定義する
UIMutableUserNotificationAction *acceptAction =
  [[UIMutableUserNotificationAction alloc] init];

acceptAction.identifier = @"ACCEPT_IDENTIFIER";

acceptAction.title = @"Accept";

// Given seconds, not minutes, to run in the background
// UIUserNotificationActivationModeForegroundを指定すると、選択時にアプリを起動する
acceptAction.activationMode = UIUserNotificationActivationModeBackground;

acceptAction.destructive = NO;

// If YES requires passcode, but does not unlock the device
acceptAction.authenticationRequired = NO;

Categoryの作成方法

複数のアクションを登録したカテゴリを作成する
例えば: - メールカテゴリだと、返信アクション、アーカイブアクションなど登録 - 友達申請用のカテゴリだと、承認アクション、保留アクションなど登録
UIMutableUserNotificationCategory *inviteCategory =
  [[UIMutableUserNotificationCategory alloc] init];

inviteCategory.identifier = @"INVITE_CATEGORY";

[inviteCategory setActions:@[acceptAction, maybeAction, declineAction]
  forContext:UIUserNotificationActionContextDefault];
UIUserNotificationActionContextDefault ボタンのサイズが普通 UIUserNotificationActionContextMinimal ボタンのサイズが若干小さめ

定義したUserNotificationの登録

UIApplicationにActionを登録したCategoryを設定したSettingを登録する
NSSet *categories = [NSSet setWithObjects:inviteCategory, alarmCategory, ...

UIUserNotificationSettings *settings =
  [UIUserNotificationSettings settingsForTypes:types categories:categories];

[[UIApplication sharedApplication]
  registerUserNotificationSettings:settings];

カテゴリを指定したNotificationの発行

Remote Notification

apsにcategoryを追加して飛ばす
{
  "aps" : {
    "alert" : "You’re invited!",
    "category" : "INVITE_CATEGORY",
  }
}

Local Notification

UILocalNotification *notification = [[UILocalNotification alloc] init];

...
notification.category = @"INVITE_CATEGORY";

[[UIApplication sharedApplication] scheduleLocalNotification:notification];

Handling Notification Action

iOS7ではアプリが起動して無い場合
application:didFinishLaunchingWithOptions:
application:didReceiveRemoteNotification:fetchCompletionHandler:
アプリが起動している場合は
application:didReceiveLocalNotification:
application:didReceiveRemoteNotification:
application:didReceiveRemoteNotification:fetchCompletionHandler:
iOS8では
// Push Notificationの場合
- (void)application:(UIApplication *)application
  handleActionWithIdentifier:(NSString *)identifier
     forRemoteNotification:(NSDictionary *)notification
         completionHandler:(void (^)())completionHandler {
    if ([identifier isEqualToString:@"ACCEPT_IDENTIFIER"]) {
      [self handleAcceptActionWithNotification:notification];
    }
    // Must be called when finished
    completionHandler();
}

// Local Notificationの場合
- (void)application:(UIApplication *)application
   handleActionWithIdentifier:(NSString *)identifier
  forLocalNotification:(UILocalNotification *)notification
   completionHandler:(void(^)())completionHandler {

}
を使う。identifireにActionで選択されたIDが入ってくる。

Remote Notifications

User
  • Requires call to registerUserNotificationSettings:
Silent
  • Info.plist UIBackgroundModes array contains remote-notification

登録方法

×[myApp registerForRemoteNotificationTypes:someTypes]; [myApp registerForRemoteNotifications]; [myApp registerUserNotificationSettings:mySettings];

Location Notifications

一定エリアに入ったタイミング、出るタイミング
一定エリアに入ったら毎回通知するか、一回だけ通知するか選択可能
以前もあったけどシンプルに実装できるようになったイメージ

使い方

UILocalNotification * locNotification;

locNotification.regionTriggersOnce = YES;

locNotification.region = [[CLCircularRegion alloc] initWithCenter:LOC_COORDINATE
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

英字キーボードで英語/かな変換を楽にするTips


英字キーボードで英語/かな変換を楽にするTips

英字キーボードに変更したけど、いろいろと不便な点が。
その一つが英字/かなの切り替え。


日本語キーボード

英字キー、かなキーがそれぞれあるので、それを押せばOK


英字キーボード

command + space で英字/かなの切り替えになる。(入力ソースの切り替え)



複数キーを押さないといけないのがだんだんとストレスに!!



KeyRemap4MacBook

設定方法はKeyRemap4MacBookで行う。
https://pqrs.org/macosx/keyremap4macbook/index.html.ja



設定方法

以下の項目にチェックをする
Use Command_R as KANA/EISUU (toggle)

Facebook Tweaksを使ってみた

Tweaksとは

iOSアプリ開発において、UXなどインタラクティブな操作において、
微妙なパラメータ調整を行いたい場合、簡単に設定画面を作って、再度ビルドすることなく、
値を変更して動作確認するためのライブラリです。(たぶん)

FacebookのPaperでも使われているそうです。

Github

https://github.com/facebook/Tweaks

インストール

pod 'Tweaks'

使い方

値の取得

引数は、カテゴリ、コレクション、名前、値(複数)

CGFloat animationDuration = FBTweakValue(@"Category", @"Group", @"Duration", 0.5);

※リリースビルドではデフォルト値を展開するだけなので、パフォーマンス的に問題にはならない

最小、最大数

数字に対しては、値を複数していして、デフォルト値、最小値、最大値を指定することができる

self.red = FBTweakValue(@"Header", @"Colors", @"Red", 0.5, 0.0, 1.0);

バインド

微調整のパラメータが変更されたら自動で更新されます。
第一引数に対象のオブジェクト、第2引数にプロパティーを指定します。

FBTweakBind(self.headerView, alpha, @"Main Screen", @"Header", @"Alpha", 0.85);

アクション

微調整リストを選択したときの処理をBlockを使って定義する事ができる。
ただし、block内はグローバルスコープになる

FBTweakAction(@"Player", @"Audio", @"Volume", ^{
  NSLog(@"Action selected.");
});

設定画面

設定画面を表示する方法2種類

シェイクジェスチャーで表示

AppDelegate.mに以下を追加

- (UIWindow *)window
{
    if (!_window) {
        _window = [[FBTweakShakeWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    }

    return _window;
}

シミュレータでシェイクジェスチャをする場合は⌘Z

FBTweakViewControllerをモーダルで呼ぶ

モーダルで呼び出す。FBTweakViewController自体がNavigation Controllerなので、pushするとクラッシュする

FBTweakViewController* vc = [[FBTweakViewController alloc] initWithStore:[FBTweakStore sharedInstance]];
[self presentViewController:vc animated:YES completion:nil];

その他

マクロを使わずに直接オブジェクトを生成する事も可能

FBTweak *tweak = [[FBTweak alloc] initWithIdentifier:@"com.tweaks.example.advanced"];
tweak.name = @"Advanced Settings";
tweak.defaultValue = @NO;

FBTweakStore *store = [FBTweakStore sharedInstance];
FBTweakCategory *category = [store tweakCategoryWithName:@"Settings"];
FBTweakCollection *collection = [category tweakCollectionWithName:@"Enable"];
[collection addTweak:tweak];

[tweak addObserver:self];

変更通知

- (void)tweakDidChange:(FBTweak *)tweak
{
  self.advancedSettingsEnabled = ![tweak.currentValue boolValue];
}

まとめ

ちょっとパラメータで調整したいなーと思う事はこったUIを作る場合や、複数人(デザイナーさんがいる)場合に遭遇する事があります。そのときにわざわざ設定画面を作る事無くマクロ一つで作成できるのはものすごーく魅力的に思います。

いざリリースするときにコードにゴミが残るのが少し気になりそうですが、実際に使ってみてある程度パラメータが固まったら削除するすれば良いし、このライブラリが無ければ、都度ビルドするとなるとそっちの方が行けてないなーと思いました。

AngularJSでローディングバーやインジケータを出す方法

AngularJSでローディングバーやインジケータを出す方法

インストール

bowerでライブラリ管理している前提です。

$ bower install angular-loading-bar --save

自分の環境ではangular-animateがなかったので、
angular-animateもインストールしました。

$ bower install angular-animate --save

使い方

app.jsなどで読み込むモジュールを宣言すればOK

angular.module('myApp', ['chieffancypants.loadingBar', 'ngAnimate'])

非表示設定

インジケータやローディングバーなど非表示にしたい場合。
Safariだとオリジナルのローディンブバーとかぶってちょっとださなかったので、
ローディングバーを非表示にしました。

インジケータ非表示

angular.module('myApp', ['chieffancypants.loadingBar'])
  .config(function(cfpLoadingBarProvider) {
    cfpLoadingBarProvider.includeSpinner = false;
  })

ローディングバーの非表示

angular.module('myApp', ['chieffancypants.loadingBar'])
  .config(function(cfpLoadingBarProvider) {
    cfpLoadingBarProvider.includeBar = false;
  })

すごく簡単にライブラリの追加が簡単になってます。

このライブラリを使ったアプリはこちら

http://app.owatter.hrk-ys.net/

iOS FAQサポートツール Helpshiftを使ってみた


リンク集

アカウント作成

本家ページからアカウント作成を行う。
既にアプリを公開している場合は、App StoreのURLを入れるとアプリ情報を参照してくれる

インストール

pod 'Helpshift', '4.2.0'    

導入

初期処理

他のサービス同様にアプリ起動時にAPI Key、APP IDを指定する
Push通知は使わなければ設定しなくても良い
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ... 省略

    [Helpshift installForApiKey:@"<YOUR_API_KEY>"  domainName:@"<YOUR_COMPANY>.helpshift.com" appID:@"<YOUR_APP_ID>"];


    if (launchOptions != nil) //handle when app is not in background and opened for push notification.
    {
        NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        if (userInfo != nil && [[userInfo objectForKey:@"origin"] isEqualToString:@"helpshift"])
        {
            [[Helpshift sharedInstance] handleRemoteNotification:userInfo withController:self.window.rootViewController];
        }
    }
}

- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if (!deviceToken) return;

    [[Helpshift sharedInstance] registerDeviceToken:deviceToken];
}



- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    //Helpshift::handle notification from APN
    if ([[userInfo objectForKey:@"origin"] isEqualToString:@"helpshift"]) {
        [[Helpshift sharedInstance] handleRemoteNotification:userInfo withController:self.window.rootViewController];
    }
}

問い合わせ機能

お問い合わせ機能では、基本的にユーザとのメッセージのやり取りの他に、スナップショットを添付させたり、レビュー依頼を出せたりする。
[[Helpshift sharedInstance] showConversation:self withOptions:nil];
メッセージ投稿フォームが起動する

どうやらNameの所は数字とか入力できないもよう。
設定で名前やメールアドレスの入力フォームを非表示にできる
SETTINGS > Allow anonymous issues

OPE

ISSUES
問い合わせされた内容が表示される
  • ステータス管理
  • タグ機能
  • メモ
  • 問い合わせをベースにFAQを作成する事も可能
  • キャプチャーを撮ってもらうように促して、キャプチャーを添付してもらう事も可能
  • Push通知
  • アプリ内通知(アプリを開いてるとき)
  • レビュー依頼
ステータス
ユーザの問い合わせでステータスがオープンになり、その後メッセージのやり取りが行われる。 最後はユーザ側のアクションでCloseとなる
  1. open
  2. メッセージをやり取り
  3. オーペレータがResolvedに変更
  4. ユーザがCloseする

FAQ

[[Helpshift sharedInstance] showFAQs:self withOptions:nil];

OPE

特に困る事はないけど、新規作成したときは「非公開」になってるので、公開にする

国際化

HSLocalizationフォルダを追加する
Pods/Helpshift/helpshift-ios-4.2.0/HSLocalization
10種類の言語ファイルがあるので、必要なやつだけ追加する。
自分の場合はEnglishだけで、日本語を表示してるので、英語意外は全部削除。
そして、日本語の内容をコピペする。(やはり日本語辺なので修正した方が良さそう)

デザイン

HelpshiftConfig.plist もしくは HelpshiftConfigDark.plist を追加する
HelpshiftConfigDark.plistを追加する場合は、ファイル名を’HelpshiftConfig.plist'に変更する
Pods/Helpshift/helpshift-ios-4.2.0/HSThemes
全体的なデザインはデフォルトのままなので、あまり気にならないが、フォントだけどうしてもきになったので、 すべてヒラギノに変更
  • ヒラギノ角ゴ ProN W3
  • ヒラギノ角ゴ ProN W6

アプリの評価

OPEのSETTINGSからアプリの評価を促すダイアログの表示条件を指定できる
  • 5, 10, 15, 20, 30回目の起動
  • 3, 7, 10, 15, 20, 30日後の起動


実際に導入したアプリはこちら

DeskSlide

スマホとPC間のデータ転送が簡単に行えます。
URLなどのテキストや、画像ファイルなどが転送できるアプリです。

iOS7 画面遷移のカスタマイズ 初級

登場人物

  • UIViewControllerAnimatedTransitioning (アニメーションコントローラ)
  • UIViewControllerContextTransitioning (画面遷移コンテキスト)
  • UIViewControllerTransitioningDelegate (画面遷移デリゲート)

実装

1.どのようなアニメーションを行うかを定義したクラスを作成

UIViewControllerAnimatedTransitioningを継承したクラス

@interface HYFadeAnimationController : NSObject <UIViewControllerAnimatedTransitioning>
@end

実装はheaderファイル通り

アニメーション時間を指定

- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext;

実際のアニメーションを指定

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
{

    // 遷移元と遷移先のViewControllerを取得

    UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
   UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];


    // 遷移先のViewを追加
    UIView* containerView = [transitionContext containerView];
    [containerView insertSubview:toVC.view belowSubview:fromVC.view];

    // アニメーションを指定

    [UIView animateWithDuration:[self transitionDuration:transitionContext]
                 animations:^{
                     fromVC.view.alpha = 0.0;
                 } completion:^(BOOL finished) {
                     [transitionContext completeTransition:YES];
                     fromVC.view.alpha = 1.0;
                 }];
}

2.遷移先のViewControllerのTransitioningDelegateにUIViewControllerTransitioningDelegateを指定

どの遷移で、どのアニメーションコントローラを利用するか指定する(今回は遷移元に実装)

@interface HYViewController () <UIViewControllerTransitioningDelegate>
@end

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"showModalView"]) {
        [[segue destinationViewController] setTransitioningDelegate:self];
    }
}


- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:    (UIViewController *)dismissed
{
    return [[HYFadeAnimationController alloc] init];
}

ReactNativeでAndroid対応する話

前提 ReactNativeでiOS版のアプリをリリースしていて、Android版をリリースする話 トラブルシューティング Build.VERSION_CODES.Q が存在しないエラー compileSdkVersionを29以上にすると解決 メモリー足りないエラー Execu...