ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareで通知センターを利用する

 Xojo / Real Studio Trial and Error

CocoaのDeclareで通知センターを利用する

目次
 はじめに

 今迄、Real Studio(Xojo)の標準機能で実現できないケースでは、主にDeclareを使ってきましたが、それらは全てCarbonベースのものでした。
 それがここ最近、使いたい機能が(探し方の問題なのかもしれませんが)Carbonでは見つからず、Cocoaでなら見つかる、という事例も増えてきていることから、CocoaベースのDeclareについて、少し調べてみました。

 なお検証には、Real Studio 2011 Release 3を用いています。(Mac mini + OS X 10.8 Mountain Lion)


 CocoaのDeclare記述

 CocoaのDeclare記述は、Carbonとはちょっと違いますので、まず始めにメモっておきます。
 Objective-cでは、一般に、オブジェクトにメッセージを送るという形で式を記述します。
個々のメッセージは、メッセージセレクタ/セレクタ/メソッド名等と呼ばれるが、ここでは主に、Real Studioに合わせてセレクタと呼ぶ。
 そのため、オブジェクトの取得、セレクタの宣言、セレクタの処理、という3段階が必要になります。
注)オブジェクトの取得はクラスメソッドの場合のみ必要。(インタンスメソッドは、通常それより前に取得したインスタンスに対しての操作になるため。)
// 下行は、Objective-cでの記述
// NSApplication *sA = [NSApplication sharedApplication];

// 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr

// 1. NSApplicationオブジェクトを取得
Dim sA As Ptr = NSClassFromString("NSApplication")
// 2. NSApplicationのセレクタであるsharedApplicationを宣言
Declare Function SharedApplication Lib "Cocoa" Selector "sharedApplication" (receiver As Ptr) As Ptr
// 3. sharedApplicationセレクタの処理(引数にはメッセージの受け手であるsAを指定し、戻り値は同じくsAを指定。)
sA = SharedApplication(sA)
 他に、気付いた点としては、

 通知センターを使ってみる

 Real Studio(Xojo)言語リファレンスのDeclareの項には、About Boxを表示するサンプルが載っていますが、ここでは、通知センターを使ってみることにしました。
 通知センターは、10.8 Mountain Lionから導入された、メールやアップデートのお知らせが画面右上に表示されたり、メニューバー右端の(三の字に似た)アイコンをクリックすると一覧が表示される、というものです。(詳細はこちら。)

 Cocoa(Objective-c)では、以下のようなシンプルなコードで実現可能です。(以下は一例です。)
- (void)sendNotification {
	NSUserNotification *notification = [[NSUserNotification alloc] init];
	[notification setTitle:@"Hello World"];
	[notification setInformativeText:@"my message"];
	[notification setDeliveryDate:[NSDate dateWithTimeInterval:5 sinceDate:[NSDate date]]];
	[notification setSoundName:NSUserNotificationDefaultSoundName];
	
	NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
	[center scheduleNotification:notification];
}

 Real Studioでの実装

 以下は、上記Objective-cのコードを、原則としてそのまま移植したものです。
(NSUserNotificationDefaultSoundNameのみ、戻り値であるDefaultSoundNameを直接指定しています。)
メソッド名: SendNotification(注:名前は任意)

Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr

Dim notification As Ptr = NSClassFromString("NSUserNotification")
Declare Function notificationAlloc Lib "Cocoa" Selector "alloc" (receiver As Ptr) As Ptr
notification = notificationAlloc(notification)
Declare Function notificationInit Lib "Cocoa" Selector "init" (receiver As Ptr) As Ptr
notification = notificationInit(notification)

Declare Sub setTitle Lib "Cocoa" Selector "setTitle:" (receiver As Ptr, id As CFStringRef)
setTitle(notification, "Hello World")

Declare Sub setInformativeText Lib "Cocoa" Selector "setInformativeText:" (receiver As Ptr, id As CFStringRef)
setInformativeText(notification, "my message")

Dim date1 As Ptr = NSClassFromString("NSDate")
Declare Function date Lib "Cocoa" Selector "date" (receiver As Ptr) As Ptr
date1 = date(date1)
Dim date2 As Ptr = NSClassFromString("NSDate")
Declare Function dateWithTimeInterval Lib "Cocoa" Selector "dateWithTimeInterval:sinceDate:" (receiver As Ptr, id1 As Double, id2 As Ptr) As Ptr
date2 = dateWithTimeInterval(date2,5,date1)
Declare Sub setDeliveryDate Lib "Cocoa" Selector "setDeliveryDate:" (receiver As Ptr, id As Ptr)
setDeliveryDate(notification, date2)

Declare Sub setSoundName Lib "Cocoa" Selector "setSoundName:" (receiver As Ptr, id As CFStringRef)
setSoundName(notification, "DefaultSoundName")

Dim center As Ptr = NSClassFromString("NSUserNotificationCenter")
Declare Function defaultUserNotificationCenter Lib "Cocoa" Selector "defaultUserNotificationCenter" (receiver As Ptr) As Ptr
center = defaultUserNotificationCenter(center)
  
Declare Sub scheduleNotification Lib "Cocoa" Selector "scheduleNotification:" (receiver As Ptr, id As Ptr)
scheduleNotification(center, notification)
 上記メソッドを、(例えば)Windowに置いたPushButtonのActionイベントから呼び出します。
 あと、Appの「Application Identifier」に、適切な文字列を設定します。(空欄だと、動作しない。)
何か適当な文字を打ち込んで、その後削除すると、com.yourcompany.yourappnameがデフォルトでセットされるようになるが、それでも問題ないようだ。
 実行した結果、とりあえず動きました。


 問題点

 前項で、とりあえず、と書いたのは、「通知がバナー表示されない」ことによります。
 メニューバー右端のアイコンをクリックして通知センターを表示してみると、一覧には上がっているので、動作はしているとみてよさそうです。
 調べてみたら、以下のサイトがヒットしました。

 参考サイト(1):objective c - Send notification to Mountain lion notification center - Stack Overflow

 つまり、「(指定をしなければ)通知を発行したアプリ(自分自身)が最前面にあると、通知が表示されない」ということのようです。
 そこで、送信後、直ちに別アプリ(またはFinder)をクリックしたところ、バナーが表示されるようになりました。

 なお、この問題を回避する方法も、上記参考サイト(1)に記載されていますが、delegateメソッドをオーバーライドする方式のため、Real Studioでの実装方法が分かりません。
 アプリの種類によっては、発行後バックグラウンドにまわすとか、直ちに終了するとかで、この問題を迂回することもできそうですが、いずれにしても、もう少し調べてみたいと思います。
追記:delegateメソッドのオーバーライドについて、こちらのページに纏めました

 考察

 CocoaのDeclareは、Cocoaでビルドしないと使えないかと思っていたのですが、Carbonでもビルドできました。
 今回の通知センターアプリも、Carbonビルドで動作しています。

 ただし、上でも触れたAbout Boxを表示するサンプルでは、パネルを閉じられなくなる、という問題が発生しました。
 なので、過去の資産を(安定性を重視して)Carbonでビルドしたい場合は、十分テストした方がよさそうです。


 macoslibについて
注)この項のみ、Real Studio 2012 Release 2を使用しています。(2011 Release 3では動作しませんでした。)
 本家のTwitterでも紹介されていたmacoslibを使えば、本件で目指していることが実現できることを確認しました。
 勿論、delegateメソッドをオーバーライドする部分も実装されています。
delegateメソッドオーバーライドの仕組みを理解するため、当該部分を実験的に抜きだしてみようかと思ったのですが、複数のクラスやモジュール等が絡み合っていて、一筋縄ではいきそうもありませんでした。実用が目的であれば、素直に使わせて頂いた方が良さそうです。

 お世話になったサイト

 貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)

 参考サイト(1):objective c - Send notification to Mountain lion notification center - Stack Overflow


 更新履歴

 2015.02.27 問題点の記述に、追記を追加
 2014.11.05 CocoaのDeclare記述に、注を追加
 2014.03.20 macoslibについて、を追加
 2013.09.02 新規作成


[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]