iPhone アプリケーションの URL スキームを調べる

Launch Center という iPhone アプリケーションがあります。

iOS 5.1 になって iPhone の設定を開けなくなったのは悲しい出来事でしたが、それでも少ない手間で目的のアプリケーションを起動することができるなかなか便利なアプリケーションです。いまさらここで詳しい使い方を書くのもあれなので、いくつか参考になるところを。

このアプリケーションはいわゆるランチャーなのですが、起動することができるアプリケーションは URL スキームを持っているかどうかで決まります。 Launch Center で対応しているアプリケーションもありますが、それ以外のアプリケーションは URL スキームを持っているかどうか調べないと分からない。

調べる方法はいくつかありますが、なかなか面倒。こういうものは人力でするものではありません。

iPhone のアプリケーションはバックアップ先の Mac に保管されていると思います。この保管されているアプリケーションの中にある、Info.plist というファイルを調べると URL スキームを持っているかどうか、持っているならどういう文字列か、ということはすぐに分かります。

iPhone のアプリケーションは実際のところ Zip ファイルで拡張子 ipa を zip に変更すれば、そのまま解凍できるというのはよく知られた話です。が、これらのアプリケーションのファイル名を変えて、解凍し、Info.plist を開き、目的の文字列を探し出すのは面倒な作業です。

これらの作業(Zip に変更し、解凍)を行うスクリプトをぴよまるソフトウェアさんが公開していますが、ここまでするのも大袈裟です。

ようは Info.plist 内の特定の文字列を探し出すだけです。アプリケーションのすべては必要ありません。どうすれば、Info.plist だけを抜き取ることができるか...。AppleScript だけでは Zip ファイルを解凍せずに目的のファイルを抜き出すことはできません。

でも、python は標準で入っているよな...。python には zipfile があるよな...。

なら、両者を組み合わせればいいだけで、こういうことこそ AppleScript の得意とするところ。

アプリケーション形式の AppleScript でパッケージ内に python スクリプトを配置しています。使い方は至って単純で iPhone アプリケーション(拡張子 ipa。複数可)をこのアプレットに放り込むだけ。もしくは、アプレットをダブルクリックで起動し、拡張子 ipa のファイルを選択するだけです。

処理が終了すると、デスクトップ上に「URL Schemes.csv」というファイルを作り、その中に URL スキームを書き出します。あとは、テキストエディタで開くなり、CSV ファイルなので Numbers や Excel で開くなりしてください。

ま、いつものごとく特別にエラー処理はしていないのでご利用は、ご自身の責任でお願いします。

AppleScript Editor で作る Cocoa アプリケーション

Mac OS X 10.7 を導入したのがそもそも遅かった...というのもあるのですが、旬の話題はそろそろ次の OS ですか。そうですか。そうですか。

そんな話題で盛り上がっている中、AppleScriptObjC...略して ASOC です。

AppleScriptObjC...っていうのはいったいなんなのか?

というところから話を始めますが、そもそも AppleScript というのは Mac を使う上で面倒な『日々の同じ作業を自動化する』ために生まれたプログラミング言語。いわゆるバッチ処理ですね。

Mac で作業するっていうことはいろいろなアプリケーションを扱うってことで、Mac での作業を自動化するということは、いろいろなアプリケーションを自在に操る必要があるわけです。その『アプリケーションを自在に操る』ために用意されたのが AppleScript です。

大雑把にいってしまうと、AppleScript というのはいろいろなアプリケーションを繋ぎ合わせるためのプログラミング言語。グルー言語(糊言語)なんていったりしますが、AppleScript はまさしく糊でいろんなアプリケーションを連携させることに長けています。

AppleScript は年月を積み重ねることで様々な機能が付加され続けてきましたが、シェルスクリプトと連携することができるようになったおかげで Perl や Python、Ruby などのスクリプト言語との連携もでき、Safari を通じて JavaScript を利用することができるようにもなりました。グルー言語の面目躍如といったところでしょうか。AppleScript 単体ではできない処理もアプリケーションや他のスクリプト言語の力を借りて処理が行えたりします。

do shell script 命令を利用することで他のスクリプト言語を活用することはできたのですが、Mac OS X の Cocoa フレームワークの機能を利用することはできませんでした。が、Mac OS X 10.6 から追加された ScriptingBridge というフレームワークを利用することにより、ついに AppleScript からも Cocoa の機能を利用することができるようになったのです。

Mac OS X 10.6 では Xcode でしか AppleScriptObjC のアプリケーションを作ることができませんでしたが、Mac OS X 10.7 からは AppleScript Editor で Cocoa アプリケーションが作れるようになりました。

もう、AppleScript なんでもアリです。というか、こんな面白いオモチャいじられずにおられるものか。

では、さっそく AppleScript Editor で Cocoa アプリケーションを作ってみましょう。

AppleScript Editor を起動し、「ファイル」メニューの「テンプレートから新規作成」メニューにある「Cocoa-AppleScript Applet.app」をクリックします。

template_menu.jpg

すると、保存されているテンプレートをもとに新しいアプレットが作成され、編集が行えるようになります。

テンプレートからアプレットが作成されたら、すでに Cocoa の機能を利用できる環境が整っています。おもむろに以下のコードを記述してみましょう。

tell current application's NSDistributedNotificationCenter's defaultCenter()
    addObserver_selector_name_object_(me, "update:", "com.apple.iTunes.playerInfo", missing value)
end tell

on update_(aNotification)
    set userInfo to aNotification's userInfo
    if (|Player State| of userInfo) as text is "Playing" then
        tell me to activate
        display dialog (|Name| of userInfo as text) with title (|Artist| of userInfo as text) with icon 1 buttons {"OK"} default button 1 giving up after 5
    end if
end update_

on quit
    tell current application's NSDistributedNotificationCenter's defaultCenter()
        removeObserver_(me)
    end tell

    continue quit
end quit

Objective-C のプログラムを AppleScript のスクリプトにどのように変換すればいいかは、AppleScriptObjC Release Notes に書かれています。

スクリプトは iTunes からの通知を受け取って曲の変わり目にその曲の情報を表示するというものです。

実行は、通常のスクリプトと同じように「スクリプト」メニューの「実行」を選択すればいいのですが、選択するとシートが表示されます。

run_application_sheet.jpg

ここでは必ず「アプリケーションを実行」を選択してください。「スクリプトを実行」を選択すると、通常の AppleScript として実行され、Cocoa の機能は利用できません。

シートの表示が煩わしい場合は、「スクリプト」メニューの「アプリケーションを実行」を選択すればシートは表示されず、すぐに実行されます。

スクリプトはアプリケーションとして実行されるので、明示的に終了させないといつまでも起動したままになります。通常のアプリケーションと同じようにアプリケーションメニューの「終了」を選択します。

アプリケーションとして実行されるということは AppleScript Editor でのデバック機能は利用できないということです。結果や実行途中のイベントも取得できません。これが困ったところで、現在のところデバックするには log 命令を利用して Console.app にログを表示するぐらいしか方法がありません。

ほかの注意点としては、display dialog 命令で NSString を表示する際には明示的に型変換を行うといったことがあげられます。これは、NSString だけのことではなく、Cocoa のクラスを AppleScript で利用する際にはこの型の変換を常に意識しておく方がいいです。

また、current application 経由で Cocoa の機能を呼び出しているため、current application を省略することもできません(短く記述したいなら、my でも it でも可)。

総体的には手っ取り早く Cocoa の機能を使ったアプリケーションを作るには選択肢として有りだと思うのですが、デバック機能が log 命令ぐらい(ファイルに書き出したり、ダイアログも使えますが)しかないのが致命的です。GUI の構築に手間がかかるというのも、その辺りを期待していた人には問題になるかも。

Xcode で作った ASOC アプリケーションのコードをそのまま流用できないというのもなんだかなぁというところです(スクリプトそのものはコピーアンドペーストで利用できます。Xcode はスクリプトをテキストファイルとして保持しているけど、AppleScript Edito ではコンパイル済みのスクリプトファイルでないと利用できないので)。

とりあえず、Cocoa の機能を呼び出せることは分かったけど、これを使ってなにができるか?、どこまで利用できるのか?といったことが問題になってくると思います。例えば、GUI を利用したいとか、クラス間の連携だとか...。その辺りのことは、また次回にでも。

Making Application using ASOC

AppleScriptObjC の覚書で色々と気がついた所を書きましたが、それらは実際に触ってみないと分からないことだったりします。Hello World を表示するアプリケーションを作りながら、色々と確認してみます。

Xcode や Interface Builder の使い方は、ここでは取り扱いません。それらは既に優秀な解説があります。知識としては、Cocoa はじめの一歩から手に入る Become An Xcoder ぐらいの知識が必要です(後は練習問題 12 ぐらいまでができれば大丈夫です)。訳者様に感謝です。

HelloWorld アプリケーションの UI は以下のようになります。

ASOCHelloWorld_UI.png

では、多くを端折っていきます。Xcode で Cocoa-AppleScript Application の新規プロジェクトを作成したら、アプリケーションのコントローラーを追加します。「ファイル」メニューの「新規ファイル...」から AppleScript class を選択します。NSObject のサブクラスにしておきます。ファイル名は AppController としておきます。

ASOCHelloWorld_AddFile.png

AppController.applescript を開き、アウトレットとアクションを追加します。

script AppController
    property parent : class "NSObject"

    -- Outlets
    property _window : missing value
    property textField : missing value
    property helloButton : missing value

    -- Actions
    on greeting_(sender)
        textField's setStringValue_("Hello, World")
    end greeting_
end script

アウトレットは property で宣言し、値は missing value にしておきます。アクションは引数を一つ取るハンドラとして定義します。引数を取るのでアンダースコアが必要です。Objective-C で書くなら次のようになります。

IBOutlet NSWindow *window;
IBOutlet NSTextField *textField;
IBOutlet NSButton *helloButton;

- (IBAction)greeting:(sender);

これらは通常ヘッダファイル(.h)の方に記述しますが、ASOC では、一つのスクリプトオブジェクトがヘッダファイル(.h)と実装ファイル(.m)を兼ねています。だから、上記のように書けてしまいます。あと、型の指定は当然できませんし、IBOutlet や IBAction などのキーワードも ASOC では利用できません。

なら、Interface Builder はどうやってそれらを識別するのかというと、識別されません。Interface Builder 上では全てが表示されます。ハンドラやプロパティが増えると、いささか鬱陶しいことになります。

ということで、MainMenu.xib を開いて Interface Builder で UI を作成し、アウトレットとアクションを接続します。

まず、MainMenu.xib のウィンドウに Library パレットから Object を追加します。

ASOCHelloWorld_AddObject.png

この Object を選択したまま、Inspector パレットで Class を AppController にします。

ASOCHelloWorld_ClassInspector.png

これで Interface Builder で AppController で定義したアウトレットとアクションが接続できるようになります。

ASOCHelloWorld_TargetAndAction.png

このような感じになります。保存したら Interface Builder での作業は終わりです。Xcode に戻って「ビルドと実行」を行います。アプリケーションが起動したら、ボタンを押してみてテキストフィールドに「Hello, World」と表示されるのを確認してください。

ASOCHelloWorld_UI.png

以上の作業は、AppleScript Studio での作業とは全く異なります。というより、Cocoa/Objective-C でアプリケーションを作るのとほとんど同じです。その気になれば、バインディングも使えます。

では、このアプリケーションを叩き台に色々と調べてみます。まず、スクリプトオブジェクトの外にハンドラを定義します。

on greeting()
    display dialog "Hello, World"
end greeting

greeting_ からこのハンドラを呼び出すように変更します。

on greeting_(sender)
    -- textField's setStringValue_("Hello, World")
    greeting()
end greeting_

実行してもエラーになると思います。これはどのようにしても無理なようで、スクリプトオブジェクト外にあるハンドラは呼び出すことができません。では、どうするかというとスクリプトオブジェクトにしてしまいます。

script HelloWorldDialog
    on greeting()
        display dialog "Hello, World"
    end greeting
end script

このようにしておけば、通常のようにスクリプトオブジェクトのハンドラを利用できます。

on greeting_(sender)
    -- textField's setStringValue_("Hello, World")
    HelloWorldDialog's greeting()
end greeting_

つまり、これはクラスの定義ではありません。スクリプトオブジェクトの定義です。ゆえに、このスクリプトオブジェクト内ではメソッドを作成するように引数の数だけアンダースコアは必要ありません。

しかし、下手にこのスクリプトオブジェクトの親を指定してしまうと、クラスとして扱われるようになってしまいます。

script HelloWorldDialog
    -- NSObject などを継承するとクラスになる
    property parent : class "NSObject"

    on greeting()
        display dialog "Hello, World"
    end greeting

    on greeting_(yourName) -- 引数があるのでアンダースコアが必要になる
        display dialog "Hello, " & yourName
    end greeting_
end script

スクリプトオブジェクトをそのまま利用するか、クラスとして利用するか。どちらも一長一短です。クラスとして利用するなら、別のファイルにしていても property で指定するだけでそのクラスのメソッド(ハンドラ)が利用できます。が、メソッドの命名規則は Objective-C に準じます。

他方、スクリプトオブジェクトとして利用すると、Objective-C の命名規則から逃れられますが、別ファイルにしたときに読み込みが面倒になります。awakeFromNib などを利用して読み込みますが、path to me は利用できないので、NSBundle を利用します。

on awakeFromNib()
    -- load script object.
    tell NSBundle's mainBundle()
        set theFile to pathForResource_ofType_("HelloWorldObject", "scpt")
    end tell
    set HelloWorldObject to (load script (theFile as text) as POSIX file)
end awakeFromNib

AppleScript の me は ASOC ではクラス自身を表すので、path to me は利用できません。また、上記では pathForResourceofType が返した NSString を AppleScript の text に型変換しています。AppleScript では NSString をそのまま利用できないようです。

Cocoa/Objective-C では色々と便利な関数が用意されています。それらは、ASOC では利用できません。例えば、矩形を表す NSRect を作成する NSMakeRect といった関数は使えません。これらはどのように作るのかというと、AppleScript の record クラスで代用します。

set rect to {origin:{x:10, y:10}, |size|:{|width|:100, height:100}}

このような record を作り、Objective-C のメソッドに渡せばいいようです。NSRange、NSSize、NSPoint なども同様です。NSLog は AppleScript の log 命令で代用できます。

アプリケーションを作成している時、特定のクラスを利用したい時があります。先ほどの NSBundle のように。Cocoa/Objective-C なら特に意識もしないで NSBundle のクラスメソッドを利用できたりするのですが、ASOC の場合、利用したいクラスを property で指定しておく必要があります。具体的には次のようになります。

property NSBundle : current application's class "NSBundle"

この property をどこで宣言しておくかというと、クラス(スクリプトオブジェクト)の外か、クラスの property として宣言します。

-- スクリプトのトップで宣言
property NSBundle : current application's class "NSBundle"

script AppController
    property parent : class "NSObject"
    -- クラスで宣言
    -- property NSBundle : current application's class "NSBundle"
end AppController

これで NSBundle を利用できるようになります。Objective-C の import のようなものかと思うけど、そうではないようで、一気にクラスを参照したいがために AppKit.h や Cocoa.h を指定してもだめなようです。

property AppKit : class "AppKit" -- 利用できない

このようにクラスを property で参照しておくと、クラスが持っている定数等が利用できるようになります。

-- NSBundle's notification key
-- log NSBundle's NSBundleDidLoadNotification
log current application's NSBundleDidLoadNotification

その際、current application を通して定数を指定するようにします。コメントアウトしている方は利用できません。NSWindow の初期化処理を参考に。

script CustomWindow
    property parent : class "NSWindow"

    on initWithContentRect_styleMask_backing_defer_(contentRect, aStyle, bufType, frag)
        continue initWithContentRect_styleMask_backing_defer_(contentRect, ¬
            current application's NSTexturedBackgroundWindowMask, ¬
            current application's NSBackingStoreBuffered, ¬
            false)

        return me
    end initWithContentRect_styleMask_backing_defer_
end CustomWindow

横長になるのは AppleScript の宿命です。このように利用します。初期化処理ではスーパークラスの初期化処理を最初に呼び出しますが、ASOC では continue を使ってスーパークラスの初期化を行います。また、初期化の最後に Objective-C では self を返しますが、ASOC では me を返します。

Cocoa/Objective-C のメソッドの中には AppleScript の予約語になっているものがあります。例えば、size や width もそうですし、set や center といった語は AppleScript で定義されています。NSWindow にはウィンドウをディスプレイの真ん中に移動させる center というメソッドがありますが、これを利用するには | でメソッドを囲むようにします。

_window's |center|()

ちなみに上記は以下のようにも記述できます。

tell _window to |center|()
|center|() of _window

どの書き方でも構いません。Objective-C は以下のようにメソッドを連続して記述することがあります。

NSString *string = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];

ASOC で同じように記述するなら、s を使った以下の書き方が分かりやすいかもしれません。

set str to NSString's alloc()'s initWithData_encoding_(theData,current application's NSASCIIStringEncoding)'s autorelease()

横長なのは Objective-C でも AppleScript でも同じですね。今回は Objective-C の視点から ASOC を見てみました。ASOC のいいところは、AppleScript で Objective-C のような構文を記述しながら、既存の AppleScript を混在できるところにあります。

on awkeFromNib()
    tell application "Finder"
        set loc to insertion location as text
        textField's setStringValue_(loc)
    end tell
end awakeFromNib

Cocoa/Objective-C ほど面倒ではなく、AppleScript Studio ほどイライラせずにすみます。PyObjC のプロジェクトテンプレートが Xcode 3 からなくなったのには驚きましたが(古い Xcode から移植しましたら使えました)。ASOC がいつまでサポートしてくれるのでしょう。AppleScript Studio や PyObjC に比べると、サポートの手間は少ないと思うのですが。

AppleScriptObjC 覚書

いまさら感がありありなのですが、AppleScriptObjC。通称、ASOC。Mac OS X 10.6 Snow Leopard とともに紹介されたので、既に登場から 1 年以上経っているわけですが。そろそろ、資料も揃ったことだろうとネット上を検索してみるが...これがなんとも少ない。

困ったものです。

日本で AppleScriptObjC をキャッチアップしているのは唯一ぴよまるソフトウェアさんぐらいしか見当たりません。

...困ったものです。とりあえず、Mac OS X Automation で公開されているチュートリアル動画を参考にいくつかアプリケーションを作ってみました。

アプリケーションを作っているときに気がついたことを箇条書きで書いていきます。

  • ASOC でアプリケーションを作るのは、Cocoa/Objective-C でアプリケーションを作るのと同じ。
  • AppleScript Studio とは異なる。
  • AppleScript の知識より Cocoa/Objective-C の知識が必要。
  • ASOC は、Cocoa/Objective-C でアプリケーションを作成したことがあるなら、すぐに理解できる(と思う)。
  • ASS アプリケーションを ASOC にそのまま移植するのは難しい。
  • 逆に Cocoa/Objective-C アプリケーションを ASOC に移植するのが簡単かというと、諸般の事情により一筋縄にはいかない。
  • ASOC は Cocoa の機能を全て利用できる...といったことを言われるが、そんなことはない。現状では利用できないものも多々ある。例えば、モーダルダイアログは利用できるが、シートは利用できない。

次にプログラムを書いているときに気がついたことなど。

  • ASOC のプロジェクトには登録されてるファイルはアプリケーションのデリゲートとして登録されている。
  • ASOC のクラスはヘッダファイル(.h)と実装ファイル(.m)がない。
  • ASOC のクラスは一つのスクリプトファイル(というより、スクリプトオブジェクト)で定義する。
  • スクリプトオブジェクト = クラスなので、一つのスクリプトファイルで複数のクラスを定義できる。
  • 継承は AppleScript の parent 属性を利用する。
  • テンプレートでは parent に NSObject が指定されているが、実はなくてもいい。スーパークラスに NSObject が密かに指定されている...みたい(継承をたどっていくと BAGenericObject に突き当たる)。
  • 親の指定がされていない AppleScript のスクリプトオブジェクトを継承元に指定することができる。
  • 継承元が指定されていない AppleScript のスクリプトオブジェクトをクラスとして扱うことができる。
  • 継承元が指定されていない AppleScript のスクリプトオブジェクトをクラスとして扱えば、クラスとして振る舞う。AppleScript のスクリプトオブジェクトとして扱えば、スクリプトオブジェクトとして振る舞う。
  • クラスで利用する変数(クラス変数やインスタンス変数)は AppleScript の property で定義する。
  • クラスのメソッドは AppleScript のハンドラで定義する。
  • Objective-C のメソッドはコロンで引数を表すが、ASOC ではアンダースコアで表す。drawRect: は drawRect_ になる。
  • このため ASOC 内でメソッドを定義した時、引数の数だけアンダースコアが必要になる。2 つの引数を取る append(x, y) があったとする。これは、ASOC のクラス内では appendWithX_andY_(x,y) といった形になる。Objective-C でメソッドを定義するのと同じだ。
  • メソッドの返り値や引数に型の指定はない。
  • Objective-C に用意されているメソッドの中には AppleScript で予約されているものがある。set や center 等。それらのメソッドを利用するには | でメソッドを囲む。
  • クラス内で他のクラスを利用するには、そのクラスを property を利用して参照する。
  • クラス(スクリプトオブジェクト)定義の外でハンドラを定義しても利用できない。Objective-C の関数のようなことはできない。
  • スーパークラスのメソッドは、continue を使って呼び出す。
  • NSRect や NSSize、NSPoint 等は AppleScript のレコードで定義できる。
  • 引数に NSArrayを取る Objective-C のメソッドには AppleScript の list クラスを渡すことができる。
  • 引数に NSDictionary を取る Objective-C のメソッドには AppleScript の record クラスを渡すことができる。
  • NSString と AppleScript の text は同じではない。引数に NSString を取る Objective-C のメソッドには AppleScript の text クラスを渡すことができる。が、NSString を AppleScript で利用するには型変換が必要(な時がある)。
  • Objective-C のメソッドは ASOC で利用できるが、簡易に利用するために用意されている関数群(NSMakeRect() や NSLog())等は、ASOC では利用できない。
  • NSTimer や通知などに利用するセレクタは文字列で指定する。その際、引数はコロンで表す。アンダースコアではない。
  • Objective-C の nil は AppleScript の missing value で代用。
  • path to me は利用できない。ASOC では me は自身のクラスを表す。
  • ASOC は既存の AppleScript の言語仕様を拡張しているわけではない。利用できるのは AppleScript 言語のみ。これが、いくつかの面倒を引き起こす。例えば、論理積や論理和を取りたいとき。C 言語の & や | は利用できない。
  • ASOC で Objective-C のカテゴリやプロトコルを定義することはできない。

と、思いつくままに羅列。読んだだけでは意味が分からないものもあると思いますが、細かいことはまた次回。


Snow Leopard で Dock の使い勝手が良くなったのだけど...

Snow Leopard から Dock の設定(「システム環境設定」にある)で「ウィンドウをアプリケーションアイコンにしまう」という設定が追加されました。従来まではウィンドウをしまうと Dock にずらずらっとウィンドウが並んで格納されていました。これだと Dock がウィンドウで埋められてみっともないことになっていました。

Snow Leopard から追加された「ウィンドウをアプリケーションアイコンにしまう」という設定を有効にすると、ウィンドウが Dock 内にある各アプリケーションに格納されるようになります。これで、Dock がいろんなアプリケーションのウィンドウで埋め尽くされることがなくなって、快適...なはずなのですが、問題はこのようにしてアプリケーションに格納したウィンドウをすべて元に戻したいとき。

ちょっと調べただけなのですが、どうもアプリケーションアイコンに格納したウィンドウ全てを一度で元に戻す方法はないようで...(調査不足かもしれませんが)。

最初のうちはウィンドウを一つずつ手動で元に戻していたのですが...これが、面倒。で、Dock に格納しているウィンドウをすべて元に戻す AppleScript を書く。

Script Editor で開く

tell application id "com.apple.systemevents"
    set front_application to a reference to (processes whose visible is true and frontmost is true)
    if (count front_application) is 0 then return
    set app_id to bundle identifier of (item 1 of front_application)
end tell

tell application id app_id
    try
        set window_list to a reference to (windows whose miniaturized is true)
        if (count window_list) is 0 then return
        set miniaturized of window_list to false
    on error msg number num
        activate
        display dialog (num & ": " & msg) as text with icon 1
    end try
end tell

こういうとき、System Events があると助かります。特定のアプリケーションだけではなく、すべてのアプリケーションを対象に処理を行うことができるから。

最前面にあるアプリケーションに対して実行しますが、アプリケーションによってはエラーがでるかもです。とりあえず、うちでは使えているので無問題。

application id を利用しているので Mac OS X 10.5 以降で利用可能。それ以前の環境では application id を指定している部分を変更すれば、利用できます。

スクリプトメニューなどに入れてご笑味くださいませ。

Google のコマンドラインツールを使ってみる

Google から Google の各種サービスをコマンドラインから操作できるツール(GoogleCL)が出たようで、さっそく試してみました。

とりあえず、インストールした環境などを...。

  • Mac OS X 10.6.4
  • Python 2.6.1(Mac OS X にインストールされているもの)
  • gdata 2.0.10

python や Google Data API は、日常的に利用しているので環境が整っているのだけど、そうでないと Python から利用できる Google Data API(gdata)のライブラリのインストールから始める必要があります。Python が必須ですが、これは Mac OS X に最初から入っているもので構いません。

Python は必要だけど、GoogleCL を利用するために Python の知識はとりあえず必要ありません。Python は GoogleCL が背後で利用しているだけです。

gdata for python のインストール

以前のことなので詳細は忘れてしまいましたが...まず、gdata-python-client - Project Hosting on Google Code から gdata-2.0.10.tar.gz(2010年6月19日現在)をダウンロードします。

gdata を利用するには ElementTree というパッケージが必要なのですが、Mac OS X 10.6 にインストールされている python には既に ElementTree が入っているため、ElementTree をインストールする必要はありません。

以降、Terminal での作業になります。

Terminal を起動し、gdata-2.0.10.tar.gz のある場所に移動します。

$ tar zxvf gdata-2.0.10.tar.gz 
$ cd gdata-2.0.10/
$ sudo python setup.py install

これで Python 用の gdata ライブラリがインストールされます。

gdata さえあれば、Google の各種サービスを Python で利用することができるのですが、GoogleCL は gdata を意識せずに Terminal から Google の各種サービスを利用できるようになります。

直接 Python から gdata を利用するより処理は制限されますが、GoogleCL は gdata を実際に利用するより、気楽に利用できます。

GoogleCL のインストール

googlecl - Project Hosting on Google Code から googlecl-0.9.5.tar.gz(2010年6月19日現在)をダウンロードします。

以降、Terminal での作業になります。

Terminal を起動し、googlecl-0.9.5.tar.gz のある場所に移動します。

$ tar zxvf googlecl-0.9.5.tar.gz 
$ cd googlecl-0.9.5/
$ sudo python setup.py install

以上で GoogleCL を利用するためのライブラリはインストールできました。

実際に使ってみる

GoogleCL は、Terminal から利用します。最初にヘルプを参照しておくといいと思います。

$ google -h

コマンドラインからの利用は以下のようになります。

google [picasa|blogger|youtube|docs|contacts|calendar] TASK [options]

コマンド名の後に利用するサービス、その後に行う処理、最後にオプションを記述します。単純にコマンド名だけを入力すると、対話モードに移行します。

$ google[return] # 対話モードへ
> picasa list title
headerbg-1.png
sidebarbg.png
postbg.png
...
> ^D # 終了(Control-D)

サービスにより利用できるタスクとオプションは異なります。この辺りのことはヘルプに詳しいです。

では、Blogger サイトのリストを取得してみます。

$ google blogger list

Terminal で上記のコマンドを実行すると、ユーザー名を尋ねられます。blogger で利用しているユーザー名(Google アカウントのメールアドレスの @ の前の部分。もしくは、メールアドレス)を入力します。

すると、OAuth による認証を促されます。

Please log in and/or grant access vis your browser at...の後に https で始まる URL が表示されると思います。この URL をコピーし、Safari などのブラウザでアクセスします。

ブラウザで認証を行った後、Terminal に戻り、Enter(Return)キーを押すと、Blogger での記事タイトル一覧と URL が取得できます。認証に失敗すると Failed to get valid access token! と表示されて、処理は終了します。

各サービスは初回実行時にのみ認証を求めます。この認証を行っておくと、以降の操作では認証は必要ありません。

設定ファイル

GoogleCL のインストールが完了すると、ユーザーのホームディレクトリに googlecl という Finder で表示されない非表示のディレクトリが作成されます。

$ open ~/.googlecl

このディレクトリの中に config というファイルがおさめられています。これはテキストファイルで GoogleCL で利用する各種設定が記述されています。この設定ファイルの説明は googlecl-0.9.5(googlecl-0.9.5.ter.gz を解凍したディレクトリ)にある README.config に記述されています。

各サービスにアクセスし、認証を行うとこの設定ファイルにユーザー名が保存されます。また、OAuth で行った認証もこのディレクトリに保存されます。

一度、ユーザー名を入力し、認証が行われると、次回からはそれらの入力は不要になります。別のユーザー名でログインを行いたい場合は、-u オプションを使うことで別のユーザーでログインすることができます。

$ google blogger list -u ユーザー名

設定ファイルはセクションに分割されており、各設定はキーと値のペアで記述されます。セクションは [GENERAL] といった感じで角括弧で囲まれており、直前のセクションとは空行で分割されます。例えば、以下のようになります。

[GENERAL]
regex = True
...

[CONTACTS]
list_style = title,email

regex がキーで True が値になります。このキーは -n(--title) オプションを指定するときに正規表現の使用を許可します。

$ google blogger list title --title=^WWDC # WWDC で始まるタイトルを表示
WWDC のサンプル

GENERAL セクションはすべてのサービスで利用する設定を記述しておく場所です。その他、各サービスごとにセクションは作成されます。

各サービスで利用できるタスクに list があります。これは各サービスの一覧(例えば、Google Docs のファイルの一覧や Blogger のブログタイトルの一覧など)を表示するタスクです。このタスクはオプションとして表示する項目を指定することができます。

例えば、blogger のタイトルと URL を表示させたいなら次のようになります。

$ google blogger list title,url-direct

list の後で title,url-direct と指定してしていますが、この表示する項目の指定を list_style と言います。

設定ファイルには GENERAL セクションでデフォルトの表示設定が次のように指定されています。

[GENERAL]
list_style = title,url-site

list タスクで list_style を指定しない場合、この設定を利用します。一方、Contacts セクションでは list_style は次のように設定されています。

[CONTACTS]
list_style = title,email

このサービスを利用するときはこちらの設定が優先されます。list_style の指定は、各項目を , で区切ります。各項目の間に空白を入れてはいけません。各サービスにより利用できる項目は異なります。詳しくは README.txt に書かれているので参照してみてください。

AppleScript からの利用

do shell script で利用できます。ただし、デフォルトでは google コマンドが /usr/local/bin にインストールされるため、絶対パスを利用します(インストール場所を変更しているときは適宜修正してください)。

do shell script "/usr/local/bin/google blogger list"

Automator からの利用

AppleScript の do shell script から利用できるということは Automator からでも利用できるということです。

コマンドラインから Picasa に画像をアップロードするには次のようにします。

$ google picasa post --title='アルバムの名前' *.jpg

--title オプションで指定するのは既存のアルバムの名称です。上記のコマンドを実行すると、カレントディレクトリ内にある拡張子 jpg のファイルをすべて指定のアルバムにアップロードします。

このとき注意しないといけないのはアルバムの名前です。アルバムの名前の一部が重複しているとアルバムを選択する必要があります。Picasa に「Summer 2008」、「Summer 2008」という名前のアルバムが既に存在し、次のコマンドを実行すると、どちらのアルバムかを確認するために入力を求められます。

$ google picasa post --title='Summer' *.jpg
More than one match for title Summer
0) Summer 2008
1) Summer 2008
Please select one of the items by number: 1 # 数値を指定し、enter

つまり、アルバムの指定をこのように行っていると AppleScript や Automator などからでは実行できないのです(AppleScript や Automator などからでは数値の入力ができないため)。アルバムの名称は一意のものにしておくのが無難です。

一例として Finder の選択項目を Picasa にアップロードする Automator サービスを。このサービスでは「AppleScript を実行」アクションを利用します。「AppleScript を実行」アクションに以下のコードを記述します。

Script Editor で開く

-- アップロード先(Picasa ウェブアルバムで作成したアルバムの名前)
property album : "ALBUM_NAME"
-- アップロードの対象とするファイルの拡張子
property file_extensions : {"png", "jpg", "jpeg", "tiff", "tif"}

on run {input, parameters}

    if input is {} or input is {""} then
        error -128 -- 終了
    end if

    tell application "Finder"
        set file_list to {}
        repeat with this_item in input
            if name extension of this_item is in file_extensions then
                set end of file_list to quoted form of (POSIX path of (this_item))
            end if
        end repeat
    end tell

    if file_list is {} then
        --ファイルがない場合、終了
        error -128
    end if

    set AppleScript's text item delimiters to space
    set file_list to file_list as text
    set AppleScript's text item delimiters to {""}

    set the_command to "/usr/local/bin/google picasa post --title="
    set the_command to the_command & quoted form of album & space
    set the_command to the_command & file_list

    do shell script the_command

    return file_list
end run

最後に

GoogleCL のすべては README.txt、README.config および、コマンドのヘルプに記述されています。これらを熟読することをお勧めします。

わざわざ Python から gdata を 直接たたく必要がない分(Python を知らなくても使えるし)、かなり気楽に Google の各種サービスを利用することができます。また、コマンドラインからの利用なので、AppleScript や Automator との組み合わせも簡単です。

反面、利用できないサービスもありますし、利用できたとしても操作には制限があります。この辺りは今後のアップデートに期待しましょう。

Safari 機能拡張の証明書を取得する

Google Chrome を使い始めて約 2 週間。いくつか拡張機能を入れ、それなりに使い勝手が良くなり、色々な操作が Google Chrome に集約でき始めた昨今。なんで、Safari 5 が公開されて、しかも拡張機能に対応しているのでしょうか。再度、Safari を使い始める理由ができてしまった...。

今回の Safari、AppleScript 的にはなにも変わりはありません。しかし、なんといっても Safari リーダーの機能はすばらしい。利用できるページとそうでないページがありますが(これはどのようなページを作れば Safari リーダーは利用できるのでしょうか?)。

そして、正式な拡張機能への対応があります。で、早速拡張機能を使ってみようと思ったのですが...、Safari 5 のデフォルトの設定では拡張機能が隠されていますね。

拡張機能を有効にするには、最初に環境設定の「詳細」タブにある「メニューバーに開発メニューを表示」にチェックを入れます。

safari_preference.png

そして、「開発」メニューの「機能拡張を有効にする」を選択します(Safari では「機能拡張」なのですね。Google Chrome では「拡張機能」ですが)。

safari_dev_menu.png

すると、環境設定に「機能拡張」タブが追加されます。ここでインストールされた機能拡張の管理ができるようになります。

safari_extension_preference.png

ユーザーが機能拡張を利用するには、これで利用できるようになります。拡張子「safariextz」のファイルをダウンロードし、ダブルクリックすれば Safari にインストールされます。インストールされる場所は ~/Library/Safari/Extensions です。

さて。

多くの人は機能拡張をどうやって作るのか?の方に興味があると思います。機能拡張を作るには Safari の「開発」メニューにある「機能拡張ビルダーを表示」を選択します。

safari_extension_builder_menu.png

このメニューを選択するとウィンドウが表示さるのですが...多くの人は「証明書」をまだ入手していないと思います。機能拡張を作成する前に証明書を Safari Dev から入手する必要があります。そして、証明書を入手するには Safari Developer Program に入会する必要があります。

以下の手順は Mac での場合になります。

Safari Dev Center に移動し、Safari Developer Program に入会します。既に入会されているなら、ログインしてください。この辺りの手順は割愛。

ログインすると、(おそらく)ページの右の方に「Safari Extension Certificate Utility」と書かれている部分があります。

safari_extension_certificate_utility.png

「Get Started」をクリックして証明書の作成を始めます。最初に「Request a Safari Extension Certificate」というページが表示されると思います。このページに「Launch Assistant」というボタンがあります。これをクリックします。

safari_certificate_utility.png

すると、ページ内に次のようなパネルが表示されます。

safari_certificate_utility_panel.png

このパネルの手順に従って証明書を発行してもらいます。証明書の要求書を作成するため、キーチェーンアクセス.app を起動します。「キーチェーンアクセス」メニューの「証明書アシスタント...」に「認証局に証明書を要求...」というメニューがあります。

keychain_access_ceritification.png

このメニューから「証明書アシスタント」を起動します。メールアドレスと通称を入力します。「要求の処理」は「ディスクに保存」にチェックを入れます。

keychain_certificate_assistant.png

「続ける」をクリックすると保存場所を尋ねてくるので場所を選択し、保存します。これが証明書の要求書になります。保存が完了すると Safari に戻り、「Continue」をクリックします。ファイル選択ボタンが表示されるので、先ほど保存した要求書を選択し、「Generate」ボタンをクリックします。

すると、証明書を生成し始めます。少しの間待っていると証明書が生成されるのでダウンロードします。拡張子「cer」のファイルがダウンロードされるのでキーチェーンアクセスに読み込ませます(cer ファイルをダブルクリックするとキーチェーンアクセスが読み込んでくれます)。

これで Safari 機能拡張を作成する準備ができました。この証明書がないと、機能拡張のビルドができないのですね。

Safari Dev Center からは機能拡張のリファレンスやガイド、いくつかのサンプルがダウンロードできます。まずは、この辺りのサンプルを眺めてみるといいと思います。