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

 Xojo / Real Studio Trial and Error

Cocoaのプラグインで通知センターを利用する

目次
 はじめに

 前回、Declareで通知センターの利用を試みましたが、アプリが最前面にあるとバナー表示されないという問題が残ってしまいました。
 そこで、この問題がプラグインでは解消されるのかどうか、確かめてみることにしました。

 なお、(理由は後述しますが)今回の検証には、Xojo 2013 Release 2 / Xcode 4.6.3を用いています。(Mac mini + OS X 10.8 Mountain Lion)


 Cocoaプラグインを作ってみる

 Cocoaのプラグインについては、随分前(手持ちでは、REALbasic 2008には既にある)から説明があり、以前にも試したことがあったのですが、作り方がよく分からず、従って、適当に作ってビルド(当時はXcode 3)してみても、エラーが大量に出たりするので、放置していました。
 ですが、今回の実験にあたり、Cocoa対応がより進化しているであろうことを期待して、Xojoの最新版を使って、再度トライしてみることにしました。

 作成にあたっては、以前と同じようにテンプレートが使えると便利と思って探してみたのですが、見つかりませんでした。
 なので、Xojoフォルダ内の、Extras/Plugin SDK/Examplesフォルダ内を一通り俯瞰したところ、HostedPluginExampleが手頃そうだったのでXcode 4.6.3で開いてみると、エラー表示もなくビルドもできたので、使ってみたら問題なく動きました。よって、これをベースにすることとしました。

 まずは、プラグイン作成手順の(再)確認も兼ねて、簡単な処理のテスト版を作ってみました。
  1. Plugin SDKフォルダを、適当な場所にコピー
  2. Examplesフォルダ内のHostedPluginExampleフォルダを複製し、適当な名前(ここでは、NSStringTest)にリネーム
  3. HostedPluginExample.xcodeprojをXcode 4.6.3で開く
  4. REALExampleLevelIndicator.hとREALExampleLevelIndicator.mmを削除
  5. プロジェクト名をNSStringTestにリネーム(やり方は、例えば参考サイト(1)を参照。ただし、フォルダ名の変更の項は不要)
  6. HostedPluginExample.cppをNSStringTest.cppにリネーム(ファイル名選択後、もう一度クリックして名前を変更)
  7. NSStringTest.cppの中身を全文削除後に、以下をペースト
    #include "rb_plugin.h"
    
    static REALstring CatString(REALstring str1, REALstring str2)
    {
    	const char* cstr1 = REALCString(str1);
    	NSString* nsstr1 = [NSString stringWithCString:cstr1 encoding:NSUTF8StringEncoding];
    	
    	const char* cstr2 = REALCString(str2);
    	NSString* nsstr2 = [NSString stringWithCString:cstr2 encoding:NSUTF8StringEncoding];
    	
    	NSString* nsstr3 = [NSString stringWithFormat:@"%@ %@",nsstr1, nsstr2];
    	const char* cstr3 = [nsstr3 UTF8String];
    	
    	return REALBuildString(cstr3, ::strlen(cstr3));
    }
    
    REALmethodDefinition CatStringDefn = {
    	(REALproc) CatString,
    	REALnoImplementation,
    	"CatString(str1 as string, str2 as string) as string"
    };
    
    void PluginEntry(void)
    {
    	REALRegisterMethod(&CatStringDefn);
    }
    
    注1)REALCStringとREALRegisterMethodでdeprecatedのWarningが出るが、実験目的であり、とりあえず動作しているので、そのままにしている。
    注2)Cocoa以外のAPIを混在させる場合は、Cocoa部分を#if COCOA〜#endifで囲む。今回はCocoa以外の利用は考えていないので、何もしていない。
  8. ビルド(初回やリネーム後は、先にCleanを実行)
  9. DerivedData/NSStringTest/Build/Products/Debug内のlibNSStringTest.dylibを、NSStringTest/Build Resources/Mac Cocoaフォルダにコピー
    (詳細は、Plugin SDK内のPluginPackaging.rtf、Plugin Converter内のPlugin Converter Read Me.txtを参照)
  10. Plugin Converter.rbpで、プラグイン形式(rbx)に変換
    (コンソールアプリのライセンスを持っていなくても実行は可能。「-f <フォルダへのパス>」は「共有>Debug>Command Line Arguments」で指定。)
  11. Xojoフォルダ内のPluginsフォルダに、NSStringTest.rbxをコピー
  12. Xojoを起動し、新規デスクトップアプリを作成(デフォルトでCocoaになっている筈)
  13. PushButtonを配置して、Actionに「MsgBox CatString("Hello","World")」と記述
  14. 実行
 結果、文字列を連結したメッセージを含むダイアログが表示されることを確認しました。


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

 早速、前項のサンプルに通知部分を実装してみたのですが、何も表示されませんでした。
 どうも、「通知センターを利用するアプリケーションは、バンドル形式でなければならない」ということのようです。
 そこで、何か回避方法がないか調べてみたら、以下のサイトがヒットしました。

 参考サイト(2):norio-nomura/usernotification - GitHub

 これはコマンドラインのアプリケーション用ですが、状況的にはよく似ていて応用できそうだったので、使わせて頂くことにしました。
  1. 前項で作成したプロジェクトのフォルダを複製し、適当な名前にリネーム(プロジェクト/ファイル名も同様にリネーム)
  2. 参考サイト(2)の「usernotification(フォルダアイコン)」をクリックし、「main.m(ファイルアイコン)」をクリック
  3. main.mの中身を、前項と同様にcppファイルにペーストして、全文置き換え
  4. 先頭部分に以下を追加
    #include "rb_plugin.h"
    
  5. 「installNSBundleHook()」メソッド内の、変数の方の「class(全部小文字)」を全て(例えば)「class1」に置き換え
  6. 「@interface NotificationCenterDelegate : NSObject」を以下に変更
    @interface NotificationCenterDelegate : NSObject {BOOL keepRunning;}
    
  7. 「@implementation NotificationCenterDelegate」の下に、以下を追加
    @synthesize keepRunning;
    
  8. 「- (void)userNotificationCenter:(NSUserNotificationCenter *)center didDeliverNotification:(NSUserNotification *)notification」メソッドの次に、以下を追加
    - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
        return YES;
    }
    
  9. 「int main(int argc, const char * argv[])」を以下に置き換え
    static void SendNotification(REALstring str1, REALstring str2)
    
  10. 「NSUserNotification *note = [[NSUserNotification alloc] init];」から「whileの閉じ括弧」までを削除
  11. 代わりに以下を追加
    const char* cstr1 = REALCString(str1);
    NSString* nsstr1 = [NSString stringWithCString:cstr1 encoding:NSUTF8StringEncoding];
    
    const char* cstr2 = REALCString(str2);
    NSString* nsstr2 = [NSString stringWithCString:cstr2 encoding:NSUTF8StringEncoding];
    
    NSUserNotification *notification = [[NSUserNotification alloc] init];
    [notification setTitle:nsstr1];
    [notification setInformativeText:nsstr2];
    [notification setDeliveryDate:[NSDate dateWithTimeInterval:5 sinceDate:[NSDate date]]];
    [notification setSoundName:NSUserNotificationDefaultSoundName];
    
    NSUserNotificationCenter *center = [NSUserNotificationCenter defaultUserNotificationCenter];
    [center scheduleNotification:notification];
    
  12. 「return 0;」を削除
  13. 最下段に以下を追加
    REALmethodDefinition SendNotificationDefn = {
    	(REALproc) SendNotification,
    	REALnoImplementation,
    	"SendNotification(str1 as string, str2 as string)"
    };
    
    void PluginEntry(void)
    {
    	REALRegisterMethod(&SendNotificationDefn);
    }
    
  14. ビルド後、前項の12.迄、同様に処理
  15. PushButtonを配置して、Actionに「SendNotification("Hello World","comment from myApp")」と記述
 実行してみたところ、自身が最前面にあっても、バナー表示されることを確認しました。


 考察および留意点

 当初の目標であった「アプリが最前面にあってもバナー表示」は、プラグインでは実現可能であることが確認できました。
 ただし、「システム環境設定」の「通知」では、実行中以外は表示項目にアプリ名が表示されない、といった問題もあるので、更なる調査/実験は必要と思われます。
(追記:アプリをビルドしておけば問題ありませんでした。)(2013.09.17)
 また、バッジ制御は通知センターとは別物のようですが、(時間指定時の)バナー表示とバッジの連携等、まだ不明な点もあり、今後の課題となりそうです。

 なお、今回作成したプラグインは、あくまで実験用で、体裁としては十分ではありません。
 少なくともdeprecatedは解決し、Xcodeプロジェクト設定の最適化、Releaseへの変更も行うべきでしょう。(場合によってはCarbonへの対応も。)
 実用目的で利用する場合は、それらを含めた総合的な対策が必要となります。


 お世話になったサイト

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

 参考サイト(1):Xcode4のプロジェクト名変更方法 : NAGAOKA STATION
 参考サイト(2):norio-nomura/usernotification - GitHub


 更新履歴

 2013.09.17 「考察および留意点」に追記を追加。
 2013.09.10 新規作成


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