2012年 11月 の投稿一覧

アプリをiPhone5に対応した際の備忘録

iPhone5が発売されてから随分時間が経ってますが、この度アプリをiPhone5に対応したのでやったことの備忘録を書きたいと思います。

 

縦幅を568pxに変更する

アプリによって対応する箇所はいろいろ有ると思うのですが、共通するのが縦幅を568pxに変更する事だと思います。対応されてないアプリをiPhone5で起動すると上下に余白ができてしまします。

iPhone5/iOS6で、アプリの縦幅を568pxに変更する方法 – たくあん. に記載されている通りに、568pxのスプラッシュ画像(Default-568h@2x.png)を用意してプロジェクトに追加すればiPhone5で起動した場合に568pxで表示されます。

iPhone5対応のスクリーンショットを用意する

これはApp Storeに表示されるものになりますが、iTunes Connectで申請する際に、4-Inch Retina Display ScreenshotsにiPhone5で表示したスクリーンショットをアップロードすればOKです。

ITunes Connect

iPhone5対応のスクリーンショットについて | KAYAC DESIGNER’S BLOG – デザインやマークアップの話.

その他必要な対応

ポートレート、ランドスケープ両方対応しているアプリなど、アプリによってはその他にも対応が必要みたいです。

アプリをiPhone5に対応する場合の地雷ポイント一覧 | fladdict.

Windowsで使っている便利なフリーソフト

最近Windowsを使っていて便利だなーと思うフリーソフトをメモしたいと思います。

目次

  • Windows Live Writer
  • Skitch for Windows Desktop
  • GrepReplace
  • KanjiTranslator
  • ProcessExplorer
  • SpaceSniffer

Windows Live Writer

オフラインでもブログの作成・編集ができる便利な無料ブログ編集ツールです。MacだとMarsEditが有名ですが、WindowsだとWindows Live Writerを使っている方が多いようです。

スクリーンショット_111812_065245_PM

無料ブログの編集はWriter – Windows Live on MSN.

MarsEdit 3 – Desktop blog editing for the Mac..

Skitch for Windows Desktop

Mac版は有名ですが、Windows版も最近リリースされました。ブログ書くときはSkitchWindows Live Writerで事足りるなと感じています。使い方については Skitch for Windows Desktop と Skitch for Windows 8 登場 | Evernote日本語版ブログ. が非常に参考になります。

1

Skitch | Evernote.

GrepReplace

GrepReplace は、簡単に複数のテキストファイルの中身に対して置換を行えるツールです。インターフェイスがわかりやすいのと、ポータブルで使える点がいいなと思っています。
最近はWEBプログラムのお仕事が多いのですが、コーダーさんから頂いたHTMLファイルを一括でテンプレート化(ヘッダーやフッターを置換)するときによく使います。

2

GrepReplaceの詳細情報 : Vector ソフトを探す!.

KanjiTranslator

KanjiTranslatorは、大量のファイルの文字コード(及び改行コード)を一括して変換するツールです。使用頻度は少ないですが、まえにコーダーさんから頂いたファイルの、METAのエンコードとファイルのエンコードが違うことがあって、参ったなーと思った時に使いました。

3

文字コード変換ツール「KanjiTranslator」(フリーソフト).

Process Explorer

Process Explorer は、実行中のプログラムの状態を調べるツールです。タスク マネージャーでも実行中のプログラム (プロセス) を確認することができますが、Process Explorer はタスク マネージャーと違って、プロセスに関連する様々な情報が確認できます。そのため、アプリケーションの実行に関わるトラブルシューティングを行うときなどに役立ちます。
Eclipseを使っているときに、動作が重かったので原因を調べる時に使いました。

4

Process Explorer.

SpaceSniffer

SpaceSnifferはハードディスクの容量を可視化してくれるソフトです。こちらもポータブルでしかも、高速なのでよく使っています。知らず知らずのうちに、画像ファイルやPDFなど溜まってしまうのでSpaceSnifferで容量確認しています。あと、Eclipseのワークスペースフォルダも知らないうちに数GBになっていることが有るので、SpaceSnifferで確認して削除するようにしています。

5

SpaceSniffer, find lost disk space the easy way..

最後に

前からよく使っているフリーソフト。

  • afx [ファイラー]
  • Cassava [CSVエディター]
  • clnch [コマンドランチャー]
  • cse [DBクライアント]
  • DF [差分表示ソフト]
  • DokanSSHFS [マウントソフト(SSHでリモート環境のディレクトリをマウントできる)]
  • putty [ターミナルソフト]
  • radish [メールサーバー]
  • sakura editor [テキストエディター]
  • svn-win [Windows版svnクライアントコマンド]
  • tail [Windows版tail]
  • vim [テキストエディター]
  • winscp [scpソフト]
  • meadow [テキストエディター]
  • eclipse [IDE]
  • VMWare Server [仮想環境ソフト]

最近、Windows環境をリストアしたらすごく軽くなったのでMacもいいけど、Windowsも使いやすいなと思っています。

Windows7でシンボリックリンクを使う

Windosに標準でシンボリックリンク機能有るの知らなかったのですが、Vistaから標準で使えるようです。

Windows Vista/Windows Server 2008でシンボリック・リンクを作成する - @IT.

ファイルへシンボリックリンクを作成する

mklink リンク(TO) ターゲット(FROM)

ディレクトリへシンボリックリンクを作成する

mklink /d リンク(TO) ターゲット(FROM)

シンボリックリンクを削除する

del リンクファイル
rd リンクディレクトリ

PHP4環境でのTwitter API1.1対応

PHP4の環境でTwitter API1.1対応した時の備忘録です。

現状

http://api.twitter.com/1/statuses/followers.format
  • ↑APIを使ってアカウント毎(都道府県の)に、フォローワーを取得
  • ユーザーのscreen_nameが有るかチェック
  • screen_nameが有ったら特定の処理

という事をやっていました。

今後

まずはoauth対応が必要

developerサイトでコンシューマ登録(Consumer key、Consumer secret、Access token、Access token secret取得)し、oauthが使えるようにする。

自分のアカウント情報わかればいいので、コールバックは設定なし(developerサイトで取得したAccess tokenのみでOK)

どのAPIを使うか

もともと、statuses/followers.formatは非推奨だったようで且つAPI1.1のドキュメントには使えると書いてないし、
API1のドキュメントにも GET followers/ids and GET users/lookup. 使ってねって書いてある。

https://api.twitter.com/1.1/friends/ids.json?cursor=-1&screen_name=twitterapi

↑からid一覧が取得できるのでそこから

https://api.twitter.com/1.1/users/lookup.json?screen_name=twitterapi,twitter

↑を使って、screen_nameを取得する。
※100ユーザーまで一度に調べれる(カンマ区切りでパラメーター)

疑問

APIのリクエストリミット制限に引っかかるのでは?
  • 今までのリクエストリミット
    • OAuthなしの場合はIPアドレス当たり1時間150回、OAuthありの場合は1アカウント当たり1時間350回
  • 新しいAPIのリクエストリミット
    • ・API 1.1では、1アカウント当たり15分で“エンドポイントごとに(API毎に)”15回または180回
https://dev.twitter.com/docs/api/1.1/get/application/rate_limit_status

↑で各エンドポイント毎のリミッター分かる。

結局

制限は仕方ないと割りきって、各アカウントでfollowers/ids(リミット:15回/15分)でフォローされているidを取得して、users/lookup(リミット:180回/15分)でscreen_nameを取得する。

users/lookupはパラメーターが長くなるのでPOSTがよさそう。
OAuthのパーミッションがRead-only だとPOST出来ないよ。

Utilクラス

<?php
require_once 'HTTP/Request.php';
require_once 'Jsphon/Decoder.php';
require_once 'twitter_config.php';
error_reporting(-1);
define('REQUEST_DOMAIN',       'https://api.twitter.com');

class TwitterUtil {

    // ---------------------------------------------
    // friendships/lookup 
    // ---------------------------------------------
    function friendshipsLookup($follow_account, $screen_name) {

        if (!isset($follow_account) || !isset($screen_name)) {
            return;
        }

        // APIパラメーター
        $endPointParam = array('screen_name' => $screen_name);

        // アカウント情報取得
        $accountConfig = $GLOBALS['TWITTER_CONFIG']['ACCOUNT'][$follow_account];

        // 投げる変数類設定
        $requestParam = $this->_initOAuthParam($accountConfig);
        $requestParam += $endPointParam;

        // Signatureベーステキストの作成
        $requestUri = REQUEST_DOMAIN . '/1.1/friendships/lookup.json';
        $signatureBase = $this->_createSignatureBase($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET);

        // 最初に定義したパラメータリストからscreen_name撤去
        unset($requestParam['screen_name']);

        // Signatureの作成
        $keys = $this->_rawurlencode($accountConfig['CONSUMER_SECRET']) . '&' . $this->_rawurlencode($accountConfig['ACCESS_TOKEN_SECRET']);
        $requestParam['oauth_signature'] = base64_encode($this->_hmacsha1($keys, $signatureBase));

        // リクエスト
        $result = $this->_authRequest($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET, $endPointParam);
        return $result;
    }

    // ---------------------------------------------
    // followers/ids
    // ---------------------------------------------
    function followersIds($follow_account, $cursor) {

        if (!isset($follow_account) || !isset($cursor)) {
            return;
        }

        // APIパラメーター
        $endPointParam = array('cursor' => $cursor, 'screen_name' => $follow_account,);

        // アカウント情報取得
        $accountConfig = $GLOBALS['TWITTER_CONFIG']['ACCOUNT'][$follow_account];

        // 投げる変数類設定
        $requestParam = $this->_initOAuthParam($accountConfig);
        $requestParam += $endPointParam;

        // Signatureベーステキストの作成
        $requestUri = REQUEST_DOMAIN . '/1.1/followers/ids.json';
        $signatureBase = $this->_createSignatureBase($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET);

        // 最初に定義したパラメータリストからcursor,screen_name撤去
        unset($requestParam['cursor'], $requestParam['screen_name']);

        // Signatureの作成
        $keys = $this->_rawurlencode($accountConfig['CONSUMER_SECRET']) . '&' . $this->_rawurlencode($accountConfig['ACCESS_TOKEN_SECRET']);
        $requestParam['oauth_signature'] = base64_encode($this->_hmacsha1($keys, $signatureBase));

        // リクエスト
        $result = $this->_authRequest($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET, $endPointParam);
        return $result;

    }

    // ---------------------------------------------
    // users/lookup
    // ---------------------------------------------
    function usersLookup($follow_account, $user_id ) {

        if (!isset($follow_account) || !isset($user_id)) {
            return;
        }

        // APIパラメーター
        $endPointParam = array('user_id' => $user_id);

        // アカウント情報取得
        $accountConfig = $GLOBALS['TWITTER_CONFIG']['ACCOUNT'][$follow_account];

        // 投げる変数類設定
        $requestParam = $this->_initOAuthParam($accountConfig);
        $requestParam += $endPointParam;

        // Signatureベーステキストの作成
        $requestUri = REQUEST_DOMAIN . '/1.1/users/lookup.json';
        $signatureBase = $this->_createSignatureBase($requestUri, $requestParam, HTTP_REQUEST_METHOD_POST);

        // 最初に定義したパラメータリストからscreen_name撤去
        unset($requestParam['user_id']);

        // Signatureの作成
        $keys = $this->_rawurlencode($accountConfig['CONSUMER_SECRET']) . '&' . $this->_rawurlencode($accountConfig['ACCESS_TOKEN_SECRET']);
        $requestParam['oauth_signature'] = base64_encode($this->_hmacsha1($keys, $signatureBase));

        // リクエスト
        $result = $this->_authRequest($requestUri, $requestParam, HTTP_REQUEST_METHOD_POST, $endPointParam);
        return $result;

    }

    // ---------------------------------------------
    // application/rate_limit_status
    // ---------------------------------------------
    function status($follow_account, $resources) {

        if (!isset($follow_account) || !isset($resources)) {
            return;
        }

        // APIパラメーター
        $endPointParam = array('resources' => $resources);

        // アカウント情報取得
        $accountConfig = $GLOBALS['TWITTER_CONFIG']['ACCOUNT'][$follow_account];

        // 投げる変数類設定
        $requestParam = $this->_initOAuthParam($accountConfig);
        $requestParam += $endPointParam;

        // Signatureベーステキストの作成
        $requestUri = REQUEST_DOMAIN . '/1.1/application/rate_limit_status.json';
        $signatureBase = $this->_createSignatureBase($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET);

        // 最初に定義したパラメータリストからresources撤去
        unset($requestParam['resources']);

        // Signatureの作成
        $keys = $this->_rawurlencode($accountConfig['CONSUMER_SECRET']) . '&' . $this->_rawurlencode($accountConfig['ACCESS_TOKEN_SECRET']);
        $requestParam['oauth_signature'] = base64_encode($this->_hmacsha1($keys, $signatureBase));

        // リクエスト
        $result = $this->_authRequest($requestUri, $requestParam, HTTP_REQUEST_METHOD_GET, $endPointParam);
        return $result;

    }

    // ---------------------------------------------
    // リクエスト(GET,POST)
    // ---------------------------------------------
    function _authRequest($uri, $param, $method, $addData) {

        // HTTPヘッダーに追加するAuthorizationパラメータ作成
        $requestHeaders = array();
        foreach ($param as $k => $v) {
            $requestHeaders[] = $k . '="' . $this->_rawurlencode($v) . '"';
        }

        $requestHeader = 'OAuth ' . implode(', ', $requestHeaders);

        // PEARのRequestを使ってポスト
        $request = &new HTTP_Request($uri);

        $request->setMethod($method);
        $request->addHeader('Authorization', $requestHeader);
        if ($method == HTTP_REQUEST_METHOD_GET) {
            foreach ($addData as $k => $v) {
                $request->addQueryString($k, $v);
            }
        } else {
            foreach ($addData as $k => $v) {
                $request->addPostData($k, $v);
            }
        }
        $result = $request->sendRequest();
        if (PEAR::isError($result)) {
            return;
        }

        $json = new Jsphon_Decoder();
        return $json->decode($request->getResponseBody());

    }

    // ---------------------------------------------
    // OAuth認証共通パラメーター初期化
    // ---------------------------------------------
    function _initOAuthParam($config) {
        return array(
            'oauth_consumer_key'     => $config['CONSUMER_KEY'],
            'oauth_nonce'            => md5(uniqid(mt_rand(), TRUE)),
            'oauth_signature_method' => 'HMAC-SHA1',
            'oauth_timestamp'        => time(),
            'oauth_token'            => $config['ACCESS_TOKEN'],
            'oauth_version'          => '1.0',
        );
    }

    // ---------------------------------------------
    // Signatureベーステキスト作成
    // ---------------------------------------------
    function _createSignatureBase($uri, $param, $method = 'GET') {

        if (!isset($uri)) {
            return;
        }

        // 変数名でソート
        ksort($param);

        // Sigunatureのベーステキストを作成
        $queries = array();
        foreach ($param as $k => $v) {
            $queries[] = $k . '=' . $this->_rawurlencode($v);
        }
        $query = implode('&', $queries);

        // それぞれをURLエンコードして接続
        $signatureBase = "{$method}&";
        $signatureBase .= $this->_rawurlencode($uri) . '&';
        $signatureBase .= $this->_rawurlencode($query);

        return $signatureBase;
    }

    // ---------------------------------------------
    // URLエンコード RFC3986版
    // ---------------------------------------------
    function _rawurlencode($str) {
        $str = rawurlencode($str);
        $str = str_replace('+', ' ', $str);
        $str = str_replace('%7E', '~', $str);
        return $str;
    }

    // ---------------------------------------------
    // hash_hmac('sha1', $data, $key, true)の代わり
    // ---------------------------------------------
    function _hmacsha1($key, $data) {
        $blocksize = 64;
        $hashfunc = 'sha1';
        if (strlen($key) > $blocksize) {
            $key = pack('H*', $hashfunc($key));
        }
        $key = str_pad($key, $blocksize, chr(0x00));
        $ipad = str_repeat(chr(0x36), $blocksize);
        $opad = str_repeat(chr(0x5c), $blocksize);
        $hmac = pack('H*', $hashfunc(($key ^ $opad) . pack('H*', $hashfunc(($key ^ $ipad) . $data))));
        return $hmac;
    }

}

PEARのHTTP_REQUESTを使ってリクエストを送って、jsonはJsphonを使ってデコードしています。
PHP4の環境なので

PHP4でoAuth。Twitter APIでつぶやく。「マチルダさ~ん」 | motooLogue.

を参考に作りました。
twitter_config.phpには

<?php
$GLOBALS['TWITTER_CONFIG']['ACCOUNT']['aaa'] = array(
    'CONSUMER_KEY'        => 'asdfasdfeii83jeoasdfasd',
    'CONSUMER_SECRET'     => 'asdfase90ia3aksjdflkasdlfasdfasdfas',
    'ACCESS_TOKEN'        => '12103981-asdfasdJOE+Spassaspdoep',
    'ACCESS_TOKEN_SECRET' => 'asdfDFIELKJF38293lsdsf89DKKKLL'
);

のような感じでアカウント情報を保持するようにしました。

呼び出し元は

<?php

require_once 'twitter_util.php';

$twitterUtil = new TwitterUtil();
$data = $twitterUtil->followersIds('aaa', '-1');

echo '<pre>';
print_r($data);
echo '</pre>';
exit;

のようにリクエスト送信、レスポンス取得ができるので、各アカウントでfollowers/ids(リミット:15回/15分)でフォローされているidを取得して、users/lookup(リミット:180回/15分)でscreen_nameを取得、チェックして特定の処理を行えば対応完了となりました。

PHP4用のOAuth対応ブログが大変参考になりました。