しょぼしょぼプログラマ雑記

自分のための備忘録。 開発記録など掲載してます。 質問・ご意見・ご感想等はTwitter ( https://twitter.com/yun_hokuto ) までお気軽にどうぞ。

3D Touch(Force Touch)でアプリにショートカットを作る

iPhone6sが発売になりましたね

もうみなさん手に入れられましたでしょうか?

かく言う自分も先日、iPhone5からようやくiPhone6sに変更しました

そしてiPhone6sの目玉である「3D Touch(Force Touche)」は革新的でした

Appleは常に新しいユーザー体験をさせてくれるので好きです

そこで、今回は自分のアプリにショートカットを作成する方法を記載したいと思います


ショートカットの作り方

まずは「動的に」ショートカットを作成する方法です

AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // ショートカットを作成
    UIApplicationShortcutIcon *iconCustom = [UIApplicationShortcutIcon iconWithTemplateImageName:@"CircleR"];
    UIApplicationShortcutItem *item1 = [[UIApplicationShortcutItem alloc] initWithType:@"ITEM_1"
                                                                        localizedTitle:@"item1"
                                                                     localizedSubtitle:@"あいうえおかきくけこさしす"
                                                                                  icon:iconCustom
                                                                              userInfo:nil];

    UIApplicationShortcutItem *item2 = [[UIApplicationShortcutItem alloc] initWithType:@"ITEM_2" localizedTitle:@"item2"];
    NSArray *shortcutItems = @[item1, item2];

    // ショートカットを登録(静的ショートカットと共存)
    [[UIApplication sharedApplication] setShortcutItems:shortcutItems];
    
    return YES;
}

続いて、「静的に」ショートカットを作成する方法ですが、こちらは公式にも記載されている通り、info.plist に特定の項目を作成すれば完成です

<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemIconFile</key>
        <string></string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>DefItem1</string>
        <key>UIApplicationShortcutItemType</key>
        <string>DEF_ITEM_1</string>
    </dict>
    <dict>
        <key>UIApplicationShortcutItemType</key>
        <string>DEF_ITEM_2</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>DefItem2</string>
        <key>UIApplicationShortcutItemIconFile</key>
        <string>CirlcleB</string>
    </dict>
</array>

※ UIApplicationShortcutItemIconFileにはImageSetの名称を設定
※※ UIApplicationShortcutItemIconFileが未作成or未設定の場合、アイコンなし

info.plistに設定する値等の公式ページのURLは下記のとおりです

developer.apple.com

これでショートカットが作成されます

また、ここまでで自分が把握している情報も下記に記載しておきます

  • IconFileは35x35(px)の透過PNGを使用(@2xと@3xも用意)
  • 用意するアイコンは単色(カラーにしても黒く塗りつぶされる)
  • 「写真」や「Podcast」などのサムネイルを表示するメソッドは発見できず(非公開メソッド?)
  • アイコンはデフォルトで7つ(Add、Compose、Location、Pause、Play、Search、Share)が用意されている

ショートカットからのデリゲート

続いて、ショートカットが押された際のイベントはこちらです

AppDelegate.m


-(void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
 completionHandler:(void (^)(BOOL))completionHandler
{
    if([shortcutItem.type compare:@"ITEM_1"] == NSOrderedSame) {
        NSLog(@"shortcut item1 select");
    } else if([shortcutItem.type compare:@"ITEM_2"] == NSOrderedSame) {
        NSLog(@"shortcut item2 select");
    }
}

iOS9から追加された「application:performActionForShortcutItem」を使用することで、ショートカットイベントが受け取れます

あとは、自分のアプリに対してのアクションを記述していけばいいかなと思います。

ここでも、現時点で自分が理解している情報を掲載しておきます。

  • アプリがタスクにない場合、「application:didFinishLaunchingWithOptions」と「applicationDidBecomeActive」の間で呼ばれる
  • アプリがタスクにある場合、「applicationWillEnterForeground」と「applicationDidBecomeActive」の間で呼ばれる

ただ、今回はtypeで設定しましたが、本来はuserinfoの方が良いかもしれません (typeは別のものを設定する気がする・・・)

最後に、資料と参考にさせていただいた方のWebページへのリンクも記載しておきます

[Apple 公式資料] https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/Adopting3DTouchOniPhone/

[Qiita] qiita.com

CocoaPodsでライブラリのインストールに失敗する

タイトルの通り、CocoaPodsでライブラリのインストールをしようとおもったのですが、

Unable to locate the executable `hg` 

こんなエラーが出てしまい、インストール出来ませんでした

この内容、あまり日本語の情報が無いので、ここに記載しておきます


エラー詳細

エラーの内容を要約すると、下記のような内容になります。

インストールしようとしているライブラリは`hg(Mercurial)`を必要としていますが、
あなたのPCに入ってませんので、ライブラリをインストールできません

解決方法

PCにMercurialをインストールしてから実行すれば解決ですね

というわけでターミナルを起動してインストールコマンドを実行します

brew install mercurial

※sudoは不要

これだけです

これで無事にインストール出来ました

CakePHP3にFacebookやTwitter、Google+のSDKをComposerでインストールする方法

CakePHP3では標準でComposerがついてます

かなり便利です

ただ、まだ情報も少ない(主にCakePHP3)ので、ちょろっと記載をしてみます

CakePHP3.0.7
PHP5.5.17
サーバーOSCentOS7

あ、当然ですが、下記の条件が満たされていると言う前提ですのであしからず。

  • CakePHP3のインストールが終わっている

composer.jsonの変更

CakePHP直下にあるcomposer.jsonを変更します

{
    "name": "cakephp/app",
    "description": "CakePHP skeleton app",
    "homepage": "http://cakephp.org",
    "type": "project",
    "license": "MIT",
    "require": {
        "php": ">=5.4.16",
        "cakephp/cakephp": "~3.0",
        "mobiledetect/mobiledetectlib": "2.*",
        "cakephp/migrations": "~1.0",
        "cakephp/plugin-installer": "*",
        "google/apiclient": "1.0.*"
    },
    .
    .
    .
    .

このソースの「"google/apiclient": "1.0.*"」という部分を追加します

FacebookTwitterSDKの場合は下記の様になります(2015.07.02時点)

// Facebook
"facebook/php-sdk-v4" : "4.0.*",

// Twitter
"abraham/twitteroauth": "0.5.3",

composerによるインストール

composer.jsonの変更が終わったら、コマンドラインCakePHPのディレクトリまで移動し、下記コマンドを実行します

# composer update google/apiclient

※composerコマンドの詳しい説明はこちらのサイト様がおすすめです

ここで注意すべきなのはパラメータです

パラメータで「更新するパッケージを指定」しているところがミソです

普通にアップデートすると「CakePHP自身」もアップデートされます

企業などで開発中の場合、案件によってはバージョンが固定されているものもあると思いますので、

上記のような書き方にしました

FacebookTwitterも同様ですね

これで綺麗にインストールが終了すれば、venderディレクトリに「google」ディレクトリが作成されると思います

あとは煮るなり焼くなりお好きにどうぞー

CakePHP3でログイン後のリダイレクトページを変更する(2015/06/23 追記)

CakePHP3の公式ドキュメントにあるチュートリアルでは、ログイン処理を下記のように記載しています

<?php
// In src/Controller/UsersController.php

public function login()
{
    if ($this->request->is('post')) {
        $user = $this->Auth->identify();
        if ($user) {
            $this->Auth->setUser($user);
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Flash->error('Your username or password is incorrect.');
    }
}

ここでリダイレクト処理をしているのは下記の部分です

return $this->redirect($this->Auth->redirectUrl());

これは分かりやすいですが、問題は「$this->Auth->redirectUrl()」の部分です

これは状況に応じてリダイレクト先が変わります

詳細は下記公式ドキュメント参照

Authentication — CakePHP Cookbook 3.x documentation

ただ、ログインリンクは基本どこからでもアクセスさせるように表示させているものがほとんどではないでしょうか?

そのアクセス元のページが「ログイン後にアクセスされると困るページ」だった場合、トップへ飛ばしてあげたりしたいという

要望があり、今回の記事になっています

ただ、その前に「ログイン後の基本的なリダイレクト先」を設定する方法を記載します

AppController.php
<?php
public function initialize()
{
    $this->loadComponent('Auth', [
        'loginRedirect' => [
            'controller' => 'Books',
            'action' => 'index',
        ]
    ]);
}

この内容で「$this->Auth->redirectUrl()」が返す基本的なURLが指定できます

そして、本題の「ログイン後のリダイレクトページを変更する」です

BooksController
<?php
public function complete()
{
    $this->Auth->loginRedirect = [];
} 

これだけです

これで、リダイレクト先がサイトトップになります

ご覧のとおり、「ログイン後にアクセスされると困るページ」の処理内で「loginRedirectを空っぽにする」だけです

公式にはほとんど記載がありませんので、参考にどうぞ


CakePHP version: 3.0.6 で作成しております


※2015/06/23 追記


記載した内容だけでは確実にログインページを変更できない現象が出ました。

下記のような記述方法でログイン後のページをControllserから変更できます

<?php
public function complete()
{
    $this->Auth->loginRedirect = [];
    $session = $this->request->session();
    $session->write('Auth.redirect', ['controller'=>'Books', 'action' => 'index']);
}

Session内にある「Auth.redirect」が設定されている場合は、loginRedirectより優先されます。

詳しい内容は下記の公式ページに記載してありました

Authentication — CakePHP Cookbook 3.x documentation

CakePHP3でログイン時に特定項目の判定を追加する

※当記事内容はCakePHP3のチュートリアルを一通り作った人を対象にしています  よくわからないという方は、まずCakePHP3のブログチュートリアルを作成してください


現在、CakePHP3にて開発をしています

その開発中に「Usersテーブルを論理削除にする」という内容がありました

論理削除自体はdeletedなどの項目を加えて、それの0か1などで判定するのが一般的かと思います

しかし、実際にCakePHP3のドキュメントを見ると下記のような内容が記載されています

<?php

public function login()
{
    if ($this->request->is('post')) {
        $user = $this->Auth->identify();
        if ($user) {
            $this->Auth->setUser($user);
            return $this->redirect($this->Auth->redirectUrl());
        } else {
            $this->Flash->error(
                __('Username or password is incorrect'),
                'default',
                [],
                'auth'
            );
        }
    }
}

Authentication — CakePHP Cookbook 3.x documentation

この中でログイン認証を行っている部分は下記の通り、1行です

$user = $this->Auth->identify();

これで認証が通ったかどうかの判定をしているわけですが、この処理を外から設定するようにするには下記のようになります

AppController.php
<?php
public function initialize()
{
    parent::initialize();
    $this->loadComponent('Auth', [
        'authenticate' => [
            'Form' => [
                'fields' => [
                    'username' => 'email', 
                    'password' => 'passwd'
                ]
            ]
        ]
    ]);
}

これは、簡単に言うと「基本的にusernameとpasswordに設定されている項目で判定するよ」です

なのでこの場合、Usersテーブルには「email」と「passwd」の項目があり,

「判定項目を変更する」と言う場合は、ここの値を変更してあげれば解決するはずです

それ以外に追加したい、というのが今回の記事の内容です

現時点(2015/06/16)では、公式ドキュメントがほとんど日本語化されていませんので

調べる方は苦労されているでしょう

やり方は下記の通りです

AppController.php
<?php
public function initialize()
{
    $this->loadComponent('Auth', [
        'authenticate' => [
            'Form' => [
                'fields' => [
                    'username' => 'email',
                    'password' => 'passwd'
                ],
                'scope' => [
                    'Users.deleted' => 0,
                ]
            ]
        ]
    ]);
}

設定方法はこの部分です

'scope' => [
    'Users.deleted' => 0,
]

これでログイン認証時に「Usersテーブルのdeletedが0の場合」という処理が追加されました

他にも設定項目が追加できますので、興味のある方は下記公式ドキュメントを参照してください

Authentication — CakePHP Cookbook 3.x documentation


CakePHP version: 3.0.6 で作成しております

プロジェクトに追加したフレームワーク内のplistを読み込む方法

プロジェクトを作成した際に、フレームワークとして読み込むことはよくあるかもしれません

ただ、フレームワーク内にあるplistを読み込みたいと思って調べても、Info.plistしか持ってこれない・・・

調べてみても出てこないし、困った・・・・

そしてXcodeをいろいろ弄ってみたら出来たのでログとして記載しておきます

f:id:yun_hokuto:20150527172302j:plain

赤枠の①がプロジェクト作成時のソースコード一覧

赤枠の②が追加したフレームワークのファイル一覧

この赤枠②にある下記の3つのplistを読み込みたいというお話です

・Country.plist ・Timezone.plist ・Language.plist

まずは設定

緑枠①→緑枠②(メインプロジェクトのもの)→Build Phases→Copy Bundle Resourcesの中にある

緑枠③のプラスボタンを押下し、読み込みたいファイルを選択します。

そうすると上の画像のように一覧に表示されるかと思います。

あとはplistを読み込むだけです

NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:@"Country" ofType:@"plist"];
NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];

こんな感じですかね

これで一応取得することが出来るようになりました

参考までにどうぞ

Xcode6.3
プログラム言語Objective-C

StoryBoardを開いてから別ファイルを開く際にフリーズするバグ(Xcode6.3)

iPhoneアプリを開発している最中に起きたXcodeのバグですが、タイトルの通りです。

CocoaPodsでライブラリを入れたりしていたので、そちらの不具合かな?と思ったのですが、

下記のサイト様を発見し、原因っぽいところを修正したら起動できました。

qiita.com

どうやら、「IB_DESIGNABLE」でのカスタムレイアウトを指定をしていたところが原因らしいです。

(IB_DESIGNABLEについては、ここでは触れません)

というわけで、StoryBoardのファイルをテキストエディタ等で開き、自分で指定したカスタムレイアウト用の

クラスを指定している箇所を削除しました。

「IB_DESIGNABLE」を指定している箇所は下記のコマンドをターミナルで発行すれば、発見できるかと思います。

grep -r IB_DESIGNABLE ./

あと、この作業を行う前に「バックアップを取る&自己責任で行う」ことを忘れずに!!