MacOS X

俺のnecomimiがこんなにもAdvertiseするわけがない。

この記事はmbed Advent Calendar 2014 - Adventarの6日目の記事です。
IMG_0362.png

mbed HRM1017とnecomimiを使用して、necomimiの脳波データをiPhoneへBLEで送り、iPhoneでグラフ化して表示しました。


こんな感じ。

IMG_0389.PNG

necomimiにはTGAM1というNeuroSkyのチップ基板が内臓されており、脳波(?)でネコミミが動く・・・というガジェットです。

necomimiは無線化されていないので、Bluetoothモジュールなどをくっ付けて無線化してやる必要があるのですが、今回はそれにHRM1017を使用しました。

IMG_0342.JPG IMG_0343.JPG IMG_0349.JPG IMG_0348.JPG

necomimi <-> HRM1017 は UARTで。
HRM1017 <-> iPhone は Bluetooth LEで送り、データそのままグラフとして表示してます。

necomimiのparserはこちらのページのものをそのまま使用させていただきました。

グラフ化する際に
「脳波の実データでは、このような(* レーダーチャート)波形には、なりません。折れ線グラフには、脳波に関して、意味があるとは思えません。
集中度 リラックス度は、チップ内でなんらかの計算をした結果の数値です。その計算のパラメーターが、公開されていないので、信用していません。単なる指標です。」
「信用するのは、POWERで、eegDeltaからeegMidGammaの8点です。これを棒グラフにしたら良いと思います。」
「データは、非連続データなので、棒グラフの方が、正確です。」
「Code 0x80 Raw Wave Value は、脳波の生データのようですね。」
「poorは、信号品質で、電極がおデコにピッタリくっついているかを示しています。電極がくっついていないと、電気抵抗が増加し、シグナルの強度が減少します。poorは、0から255の数値で、数値が低いほどシグナル強度が高く、200だとおデコにくっついていないことを示しています。」

というご指摘を頂けたので、取得するのは

    short raw; // 生データ
    unsigned char power;
    unsigned char poorSignal; //信号品質

    // 脳波データ
    unsigned int eegDelta;
    unsigned int eegTheta;
    unsigned int eegLowAlpha;
    unsigned int eegHighAlpha;
    unsigned int eegLowBeta;
    unsigned int eegHighBeta;
    unsigned int eegLowGamma;
    unsigned int eegMidGamma;

だそうです。面白いですよ〜。


7日目はtoyowataさんです。よろしくお願いします。


2014/7/6 名古屋市でmbed HRM1017座談会というのがありました。

そこで、HRM1017というのがどんな感じなのかの説明を受けて、ほんの少しだけ開発っぽいことを(手ほどきを受けながら)行ってきました。
雑談もBLE/ANCS、Androidどうしよう?など、色々な話題で盛り上がりました。

概要説明でも

「医療機器など命に関わる製品としては使用しないで下さい」

「mbed HRM1017を組み込んで、『最終製品』として使用する場合は、Bluetooth SIGに申請する必要がある。お金も払う必要がある。
要は、申請を簡便にしました!ということ」

「mbed HRM1017を『そのまま』使う場合は、おっけー」

「あくまでも、mbed。製品として精密な要求がされる場合は、専用にガッツリ作り込んだモノが良いですとのこと」

「今現在、mbed HRM1017 は Peripheralにしかなれません。Centralになるには、Nordicさん待ち。とのこと」

「mbed HRM1017でANCS可能」

などなど。

BLEの内容(ブロードキャストだとどうだとか、ペアリングした場合にこう変わるよとか、BLE。Androidの国内メーカーは糞という結論に、とか)に関して も少し教えて頂き、今年一年で1番の収穫と言っても良いくらい、楽しい時間になりました。

で、mbed HRM1017を1つ購入させて頂き、家に帰ってからANCSを動かしてみようと奮闘していたのですが、クロックがnRF51822とは違うため、mbed.orgに登録されて いるnRF51822ベースの(BLE_ANCS_SDAPI )ものでは動きませんでしたが、そこもTwitterで教えてもらえ無事に動かすことが出来ました。


では、実際に ANCS(Apple Notification Center Service) で iPhoneに来た通知を mbed HRM1017 へ送ってみましょう。

mbed HRM 1017 は Mac と USB Micro B で繋ぎます。
mbed コンパイラーで、Platformの設定を nRF51822に設定しておきます。



@ytsuboi 氏が https://mbed.org/users/ytsuboi/code/BLE_ANCS_SDAPI_IRC/ で既にクロック設定済みのものを公開されているので、こちらを使わさせて頂きます。

出来上がった hex ファイルを mbed ドライブへコピーします。

Macとmbed HRM1017はUSBのMicro B で繋がっているハズなので、CoolTerm で mbed側のコンソールを見られるようにしておきましょう。

iPhoneのBluetoothをONにして、mbed HRM1017とペアリングさせます。

ペアリングが完了したら、iPhoneに通知を送ってみてください。
iPush Testというアプリが便利です。このアプリから通知を送る場合は、Local Push Testのボタンを押して下さい。
他の通知を使う場合は、テキトーに、FaceTime、Twitter、Facebook、iBeaconなんでも良いです。iPhoneに通知さえくれば。

iPhoneへ通知が来た瞬間に、mbed HRM1017へ同じ通知内容がコンソールに表示されれば成功です。



とても楽しいガジェットですよ〜。
あくまでも、ガジェット。お遊び用ですが。

Objective-Cでサーバー連携する際、画像をNSStringにするとDBにそのまま突っ込めるので、便利になります。
iOS7からは、base64カテゴリからも解放されるので、嬉しいです。
以下サンプル。
[ ViewController.m 抜粋 ]
--------------------------------------------------
//UIImageをNSStringに変換。その際に+を%2Bとする。
- (NSString *)encodeToBase64String:(UIImage *)image {
    NSData * data = [UIImagePNGRepresentation(image) base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return [[NSString stringWithUTF8String:[data bytes]] stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
}
- (UIImage *)decodeBase64ToImage:(NSString *)strEncodeData {
    NSData *data = [[NSData alloc]initWithBase64EncodedString:strEncodeData options:NSDataBase64DecodingIgnoreUnknownCharacters];
   
    return [UIImage imageWithData:data];
}
//コンバート開始
- (IBAction)startPush:(id)sender
    UIImage* image = [UIImage imageNamed:@"150"];
    NSString* _str = [self encodeToBase64String:image];
    self.textView.text = _str;
    //HTTPでPOSTする。
    [sv doPost:_str];
    //self.imageView.image = [self decodeBase64ToImage:[_str stringByReplacingOccurrencesOfString:@"%2B" withString:@"+"]];
}
//POSTしたデータをサーバー側からそのまま返してみる。
-(void)toNotifyTheResponse:(NSNotification *)notification
{
    //RailsでJSONを返す。
    //要らないダブルクォーテーションを削除
    //エスケープされている改行を改行文字に変換(エスケープ解除)
    NSString*  _str = [[notification userInfo] valueForKey:@"responseString"];
    _str = [_str stringByReplacingOccurrencesOfString:@"\"" withString:@""];
    _str = [_str stringByReplacingOccurrencesOfString:@"\\r\\n" withString:@"\r\n"];
   
    NSLog(@"%@", _str);
    NSLog(@"-------------------------------------------------------------------------------------------------");
    NSString* _str2 = self.textView.text;
    NSLog(@"%@", _str2);
    _str2 = [_str2 stringByReplacingOccurrencesOfString:@"%2B" withString:@"+"];
    if( [_str2 isEqualToString:_str] ){
        NSLog(@"YES!");
    }else{
        NSLog(@"NO");
    }
    self.imageView.image = [self decodeBase64ToImage:_str];
}
[ EOF ]
--------------------------------------------------
楽チンぽんです。
ネットを見てもあまりなかったので。
メモとして。


[ AppDelegate.m ]
--------------------------------------------
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    //AudioSesstion create
    AVAudioSession* session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    [session setActive:YES error:nil];
  
    return YES;
}

--------------------------------------------



[ MusicPlayViewController.h ]
--------------------------------------------
//
//  MusicPlayViewController.h
//  SocialMuscle
//
//  Created by hoehoe on 2012/09/05.
//  Copyright (c) 2012年 hoehoe. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import "GlobalObjects.h"
#import <AVFoundation/AVFoundation.h>

@interface MusicPlayViewController : UIViewController<MPMediaPickerControllerDelegate>
{

}

@property(nonatomic, retain)MPMediaPickerController* picker;
@property (weak, nonatomic) IBOutlet UILabel *lbl_musicArtist;
@property (weak, nonatomic) IBOutlet UILabel *lbl_musicTitle;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *btn_musicPlay;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *btn_musicPause;

- (IBAction)btn_playlistPush:(id)sender;
- (IBAction)btn_closePush:(id)sender;
- (IBAction)btn_musicPlayPush:(id)sender;
- (IBAction)btn_musicSkipNext:(id)sender;
- (IBAction)btn_musicSkipPrev:(id)sender;
- (IBAction)btn_musicPausePush:(id)sender;

@end
--------------------------------------------

[ MusicPlayViewController.m ]
--------------------------------------------
//
//  MusicPlayViewController.m
//  SocialMuscle
//
//  Created by hoehoe on 2012/09/05.
//  Copyright (c) 2012年 hoehoe. All rights reserved.
//

#import "MusicPlayViewController.h"

@interface MusicPlayViewController ()

@end

@implementation MusicPlayViewController

@synthesize picker;
@synthesize lbl_musicArtist;
@synthesize lbl_musicTitle;
@synthesize btn_musicPlay;
@synthesize btn_musicPause;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    picker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAnyAudio];
    picker.delegate = self;
   
    [picker setAllowsPickingMultipleItems: YES];
    NSString* promptTitle = NSLocalizedString(@"MUSIC_PROMPT", nil);
    //picker.prompt = @"曲を追加して下さい。";
    picker.prompt = promptTitle;
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if(musicCollection != nil){
        [self setMusicProperty];
    }
   
    if(playing == YES){
        [btn_musicPlay setEnabled:NO];
        [btn_musicPause setEnabled:YES];
    }else{
        [btn_musicPlay setEnabled:YES];
        [btn_musicPause setEnabled:NO];
    }
}

- (void)viewDidUnload
{
    [self setBtn_musicPlay:nil];
    [self setBtn_musicPause:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - MPMediaPickerController delegate

- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) collection
{
    if([collection count] > 0){
        // Set global valiables parameter
        collectionCount = [collection count];
        musicCollection = collection;

        if(musicItems == nil){
            musicItems = [musicCollection items];
        }
       
    }
    [self dismissViewControllerAnimated:YES completion:nil];
}
- (void) mediaPickerDidCancel: (MPMediaPickerController *) mediaPicker {
   
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)btn_playlistPush:(id)sender {
    [self presentViewController:picker animated:YES completion:nil];
}

- (IBAction)btn_closePush:(id)sender {
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (IBAction)btn_musicPlayPush:(id)sender {
    if(collectionCount > 0){
        //再生中
        if(playing == YES){
            [btn_musicPlay setEnabled:NO];
            [btn_musicPause setEnabled:YES];
        }else{
            [btn_musicPlay setEnabled:YES];
            [btn_musicPause setEnabled:NO];

            [self doPlayMusic];
           
            [btn_musicPlay setEnabled:NO];
            [btn_musicPause setEnabled:YES];
            [self setMusicProperty];
        }
    }
}

-(void)doPlayMusic{

    playing = YES;
    MPMediaItem* item = [musicItems objectAtIndex:selectedMusicCursor];
    NSURL* url = [item valueForProperty:MPMediaItemPropertyAssetURL];
    avAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    [avAudioPlayer play];
}

- (IBAction)btn_musicSkipNext:(id)sender {
    [avAudioPlayer pause];
   
    if(selectedMusicCursor < (collectionCount - 1)){
        selectedMusicCursor++;
    }
    //NSLog(@"cursor: %d", selectedMusicCursor);
    [self doPlayMusic];
    [self setMusicProperty];

}

- (IBAction)btn_musicSkipPrev:(id)sender {
    [avAudioPlayer pause];
   
    if(selectedMusicCursor > 0){
        selectedMusicCursor--;
    }
    //NSLog(@"cursor: %d", selectedMusicCursor);
    [self doPlayMusic];
    [self setMusicProperty];
}

- (IBAction)btn_musicPausePush:(id)sender {
    if(collectionCount > 0){
        //再生中
        if(playing == YES){
            [btn_musicPlay setEnabled:NO];
            [btn_musicPause setEnabled:YES];
           
            [avAudioPlayer pause];
            playing = NO;
           
            [btn_musicPlay setEnabled:YES];
            [btn_musicPause setEnabled:NO];
        }else{
            [btn_musicPlay setEnabled:YES];
            [btn_musicPause setEnabled:NO];
        }
    }
}

-(void) setMusicProperty
{
    //曲リスト
    //タイトルとアーティスト名表示 musicTitleとmusicArtistはラベル。
    MPMediaItem* mediaItem = [musicItems objectAtIndex:selectedMusicCursor];
   
    self.lbl_musicTitle.text = [mediaItem valueForProperty:MPMediaItemPropertyTitle];
    self.lbl_musicArtist.text = [mediaItem valueForProperty:MPMediaItemPropertyArtist];
}

@end
--------------------------------------------

[ GlobalObjects.h ]
--------------------------------------------
//
//  GlobalObjects.h
//  SocialMuscle
//
//  Created by hoehoe on 2012/09/07.
//  Copyright (c) 2012年 hoehoe. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
#import "MyAccount.h"

NSManagedObjectContext* managedObjectContextGlobal;

//BOOL callSettingViewGlobal;

NSString* intervalStringGlobal;
NSDate* recordDateGlobal;


/*  MusicPlayer Global valiables */
MPMediaItemCollection * musicCollection;
//MPMediaQuery* query;
AVAudioPlayer* avAudioPlayer;
int collectionCount;
int selectedMusicCursor;
NSArray* musicItems;
BOOL playing;

@interface GlobalObjects : NSObject

@end
--------------------------------------------


こんな感じで。


Native extensions for Adobe AIR with iOS



ProcessList.jpg


iPhoneでのNative extensionも試してみました。
Adobe AIRとObjective-C/C/C++で開発が出来ます。

Windows(C#)と比べると、かなり開発はし易いですが、まぁネイティブ側を知っておかないとダメですね。

ane-lab(AIR Native Extension is Lab codes) - Google Project Hosting に作ったサンプルをコミットさせて頂きましたので、参考にして下さい。
間違ってるかもしれないので、決して鵜呑みにしないように。


開発環境
 Xcode4
 Adobe FlashBuilder4.6

サンプルは今現在起動しているアプリケーションの一覧を表示するだけのアプリです。


作るのは3つ。

Cocoa touch static library
Flexライブラリプロジェクト(SWC)
Flexモバイルプロジェクト(iOS AIRアプリ)


FlashBuilderでの作業は基本的にWindows(C#)と変わりませんので、そちらを参照して下さい。
一応コードは貼っておきます。

FlashBuilderを使用して、Flexライブラリプロジェクト(SWC)とFlexモバイルプロジェクト(iOS AIRアプリ)を作成します。

まずはSWCから。


swc.jpg


[  ProcessExtension.as ]
------------------------
package com.chocbanana.iphone{
   
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IEventDispatcher;
    import flash.events.StatusEvent;
    import flash.external.ExtensionContext;
   
    public class ProcessExtension extends EventDispatcher{
       
        private var _ExtensionContext:ExtensionContext;
       
        public function ProcessExtension(target:IEventDispatcher=null){
            //TODO: implement function
            super(target);
            _ExtensionContext = ExtensionContext.createExtensionContext("com.chocbanana.iphone.ProcessExtension", null);
        }

        public function dispose():void{
            _ExtensionContext.dispose();
        }

        public function getProcessList():Array {
            return _ExtensionContext.call("getProcessList") as Array;
        }
    }
}
[ EOF ]
------------------------


[ descriptor.xml ]
------------------------
<extension xmlns="http://ns.adobe.com/air/extension/3.1">
    <id>com.chocbanana.iphone.ProcessExtension</id>
    <versionNumber>1.0</versionNumber>
    <platforms>
        <platform name="iPhone-ARM">
            <applicationDeployment>
                <nativeLibrary>libProcessListExtension.a</nativeLibrary>
                <initializer>initializer</initializer>
                <finalizer>finalizer</finalizer>
            </applicationDeployment>
        </platform>
    </platforms>
</extension>
[ EOF ]
------------------------



で、ANEを作成するためのadtコマンドのオプションはこちら。

[ adt-option ]
------------------------
-package -target ane libProcessList_Extension.ane descriptor.xml -swc  libProcessList_Extension.swc -platform iPhone-ARM library.swf  libProcessListExtension.a
------------------------


では、Flexモバイルアプリです。
やり方はWindowsの方とそう大して変わりません。
生成されたaneファイルとswcファイルをプロジェクトに追加しておいて下さい。


flashbuilder.jpg


[ ProcessList.mxml ]
------------------------
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark" applicationDPI="160">
   
    <fx:Script>
        <![CDATA[
            import com.chocbanana.iphone.ProcessExtension;
            import mx.collections.ArrayList;

            [Bindable]
            private var ar:ArrayList = new ArrayList();

            private var ane:ProcessExtension = new ProcessExtension();
           
            protected function btn_getProcess_clickHandler(event:MouseEvent):void
            {
                // TODO Auto-generated method stub
                this.ar.removeAll();
                try{
                    var _ar:Array = ane.getProcessList();
                    for(var i:int =0; i<_ar.length; i++){
                        this.ar.addItem(_ar[i]);
                    }
                }catch(e:Error){
                    trace(e.message);
                    trace(e.getStackTrace());
                }
            }
        ]]>
    </fx:Script>
   
    <fx:Declarations>
        <!-- 非ビジュアルエレメント (サービス、値オブジェクトなど) をここに配置 -->
    </fx:Declarations>
    <s:VGroup x="0" y="0" width="100%" height="100%" horizontalAlign="center" verticalAlign="bottom">
        <s:List id="lst_processList" width="100%" height="100%" dataProvider="{ar}"/>
        <s:Button id="btn_getProcess" label="ボタン" click="btn_getProcess_clickHandler(event)"/>
        <s:Spacer width="10" height="10"/>
    </s:VGroup>
</s:Application>

[ EOF ]
------------------------

リリースビルドして、実機にて動作する事を確認して下さい。

お疲れさまでした。

# 証明書やプロビジョニングファイルなどの説明は省いています。
# 各自で調べて下さい。

Native extensions for Adobe AIR with iOS



ProcessList.jpg


iPhoneでのNative extensionも試してみました。
Adobe AIRとObjective-C/C/C++で開発が出来ます。

Windows(C#)と比べると、かなり開発はし易いですが、まぁネイティブ側を知っておかないとダメですね。

ane-lab(AIR Native Extension is Lab codes) - Google Project Hosting に作ったサンプルをコミットさせて頂きましたので、参考にして下さい。
間違ってるかもしれないので、決して鵜呑みにしないように。


開発環境
 Xcode4
 Adobe FlashBuilder4.6

サンプルは今現在起動しているアプリケーションの一覧を表示するだけのアプリです。


作るのは3つ。

Cocoa touch static library
Flexライブラリプロジェクト(SWC)
Flexモバイルプロジェクト(iOS AIRアプリ)


xcode-project.jpg


まずはCocoa touch static libraryから。
Xcode ProjectにAdobe AIR.frameworkを追加しておきましょう。


xcode.jpg


以下参照。

[ ProcessListExtension.h ]
--------------------------------
//
//  ProcessListExtension.h
//  ProcessListExtension
//
//  Created by  on 12/02/01.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <Adobe AIR/Adobe AIR.h>
#import <sys/sysctl.h>
#import <pwd.h>

@interface ProcessListExtension : NSObject


FREObject getProcessList(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);

void contextFinalizer(FREContext ctx);
void contextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions);
void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer);
void finalizer(void** extData);

@end

[ EOF ]
--------------------------------


[ ProcessListExtension.m ]
--------------------------------
//
//  ProcessListExtension.m
//  ProcessListExtension
//
//  Created by  on 12/02/01.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "ProcessListExtension.h"
#import "InstalledApplicationPlist.h"

@implementation ProcessListExtension


/*
 * http://d.hatena.ne.jp/terazzo/comment?date=20120131
 */
FREObject getProcessList(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {  
   
    FREObject result = NULL;
    FREObject _pNameAndId = NULL;
   
   
   
    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
    size_t miblen = 4;
    size_t size;
    int st = sysctl(mib, miblen, NULL, &size, NULL, 0);
   
    struct kinfo_proc * process = NULL;
    struct kinfo_proc * newprocess = NULL;
   
    do {
        size += size / 10;
        newprocess = realloc(process, size);
       
        if (!newprocess){
           
            if (process){
                free(process);
            }
           
            return nil;
        }
        process = newprocess;
        st = sysctl(mib, miblen, process, &size, NULL, 0);
    } while (st == -1 && errno == ENOMEM);
   
    if (st == 0){
       
        if (size % sizeof(struct kinfo_proc) == 0){
            int nprocess = size / sizeof(struct kinfo_proc);
           
            if (nprocess){
               
                FRENewObject((const uint8_t*)"Array", 0, NULL, &result, nil);

                char* name = NULL;
                NSString * processID = nil;
                NSString * processName = nil;
                NSString * pNameAndId = nil;
                NSString * userName = nil;

                InstalledApplicationPlist* plist = [[[InstalledApplicationPlist alloc] init] autorelease];
               
                int j=0;
                for (int i = nprocess - 1; i >= 0; i--){
                    uid_t  p_uid = process[i].kp_eproc.e_pcred.p_ruid;
                    name = user_from_uid(p_uid, 0);
                   
                    processID = [NSString stringWithFormat:@"%d", process[i].kp_proc.p_pid];
                    processName = [NSString stringWithFormat:@"%s", process[i].kp_proc.p_comm];
                    userName = [NSString stringWithFormat:@"%s", name];
                    pNameAndId = [NSString stringWithFormat:@"%@:%@:%@", processID, processName, userName];
                   
                    if([userName isEqualToString:@"mobile"]){
                        if ([plist AppInstalled:processName] == YES){
                                FRENewObjectFromUTF8(strlen([pNameAndId UTF8String])+1, (const uint8_t*)[pNameAndId UTF8String], &_pNameAndId);
                                FRESetArrayElementAt(result, j++, _pNameAndId);
                            }
                    }
                }
                free(process);
            }
        }
    }
    return result;
}

void contextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions) {
   
    *numFunctions = 1;
    FRENamedFunction*  func= (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctions));
   
    func[0].name = (const uint8_t*) "getProcessList";
    func[0].functionData = NULL;
    func[0].function = &getProcessList;
   
    *functions = func;
}
void contextFinalizer(FREContext ctx) {
    return;
}

void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer) {
    *ctxInitializer = &contextInitializer;
    *ctxFinalizer = &contextFinalizer;
}

void finalizer(void** extData) {
   
}

@end

[ EOF ]
--------------------------------

[ InstalledApplicationPlist.h ]
--------------------------------
//
//  InstalledApplicationPlist.h
//  ProcessListExtension
//
//  Created by  on 12/02/09.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface InstalledApplicationPlist : NSObject

 - (NSDictionary*) getCacheDict;
 //- (NSArray*) installedAppsSystem;
 //- (NSArray*) installedAppsUser;

 // Bundle identifier (eg. com.apple.mobilesafari) used to track apps
 - (BOOL) AppInstalled:(NSString *) bundleIdentifier;

@end

[ EOF ]
--------------------------------

[ InstalledApplicationPlist.m ]
--------------------------------
//
//  InstalledApplicationPlist.m
//  ProcessListExtension
//
//  Created by  on 12/02/09.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "InstalledApplicationPlist.h"

@implementation InstalledApplicationPlist

/*
 * http://www.iphonedevsdk.com/forum/iphone-sdk-development/22289-possible-retrieve-these-information.html
 */
 - (NSDictionary *) getCacheDict{
     NSDictionary *cacheDict = nil;// code herect;
     static NSString *const cacheFileName = @"com.apple.mobile.installation.plist";
     NSString *relativeCachePath = [[@"Library" stringByAppendingPathComponent: @"Caches"] stringByAppendingPathComponent: cacheFileName];

     //[[NSHomeDirectory() stringByAppendingPathComponent: @"../.."] stringByAppendingPathComponent: relativeCachePath];
     NSString *path = nil;
   
     for (short i = 0; 1; i++){
         switch (i) {
             case 0: // Jailbroken apps will find the cache here; their home directory is /var/mobile
                 path = [NSHomeDirectory() stringByAppendingPathComponent: relativeCachePath];
                 break;
             case 1: // App Store apps and Simulator will find the cache here; home (/var/mobile/) is 2 directories above sandbox folder
                 path = [[NSHomeDirectory() stringByAppendingPathComponent: @"../.."] stringByAppendingPathComponent: relativeCachePath];
                 break;
             case 2: // If the app is anywhere else, default to hardcoded /var/mobile/
                 path = [@"/var/mobile" stringByAppendingPathComponent: relativeCachePath];
                 break;
             default: // Cache not found (loop not broken)
                 break;
         }
        
         // Ensure that file exists
         BOOL isDir = NO;
         if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir) {
             cacheDict    = [NSDictionary dictionaryWithContentsOfFile: path];
             return cacheDict;
         }
         /*
         if ([[NSFileManager defaultManager] fileExistsAtPath: path isDirectory: &isDir] && !isDir) // Ensure that file exists
             cacheDict = [NSDictionary dictionaryWithContentsOfFile: path];
        
         if (cacheDict) // If cache is loaded, then break the loop. If the loop is not "broken," it will return NO later (default: case)
             break;
          */
     }

    return nil;
}
/*
 - (NSArray *) installedAppsSystem {
    // Then all the user (App Store /var/mobile/Applications) apps
    NSDictionary* system = [[self getCacheDict] objectForKey: @"System"];
    NSLog(@"Installed Applications = %@",[system allKeys]);
    return [system allKeys];
    //return nil;
}

 - (NSArray *) installedAppsUser {
    // Then all the user (App Store /var/mobile/Applications) apps
    NSDictionary* user = [[self getCacheDict] objectForKey: @"User"];
    NSLog(@"Installed Applications = %@",[user allKeys]);
    return [user allKeys];
    //return nil;
}
*/

- (BOOL) AppInstalled:(NSString *) processName {
    NSString* const bundleIdentifier = @"CFBundleExecutable";

    NSDictionary* systems = [[self getCacheDict] objectForKey: @"System"];
    for(NSDictionary* _system in systems){
        NSDictionary* sysDict = [systems objectForKey:_system];
        NSString* CFBundleExecutable = [sysDict objectForKey:bundleIdentifier];
        if([processName isEqualToString:CFBundleExecutable]){
            return YES;
        }
    }
   
    NSDictionary* users = [[self getCacheDict] objectForKey: @"User"];
    for(NSDictionary* _user in users){
        NSDictionary* userDict = [users objectForKey:_user];
        NSString* CFBundleExecutable = [userDict objectForKey:bundleIdentifier];
        if([processName isEqualToString:CFBundleExecutable]){
            return YES;
        }
    }

    // If nothing returned YES already, we'll return NO now
    return NO;
}

@end

[ EOF ]
--------------------------------

Xcodeはここまで。
続いて、FlashBuilderを使用してSWCとAIRモバイルアプリケーションを作成していきます。


Snow Leopard 版 Makefileをココか ら拝借しました。

[ Makefile ]
-----
# $Id: Makefile,v 1.1 2008/08/24 21:11:32 dankogai Exp dankogai $
#
# see the URL below!!
#
# http://cestdelamerde.com/archives/22-Killing-Mac-OS-X-Swapping-How-To-Disable-dynamic_pager.html
#

CFLAGS = -no-cpp-precomp -DNO_DIRECT_RPC -framework CoreFoundation \
    -framework IOKit -lSystem.B -R -DNO_DIRECT_RPC dynamic_pager.c \
    -I/Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers \
    -I/Developer/SDKs/MacOSX10.6.sdk/usr/include

all:    dynamic_pager

dynamic_pager.c:
    curl -O http://cestdelamerde.com/uploads/dynamic_pager.c

dynamic_pager:    dynamic_pager.c
    cc $(CFLAGS) -o dynamic_pager

clean:
    rm dynamic_pager

install: dynamic_pager
    mv /sbin/dynamic_pager /sbin/dynamic_pager.apple && \
    /bin/cp -p /sbin/dynamic_pager.apple . && \
    install -m 0555 -o root -g wheel dynamic_pager /sbin

uninstall: dynamic_pager.apple
    /bin/chmod +w /sbin/dynamic_pager && \
    /bin/rm -f /sbin/dynamic_pager && \
    /bin/cp -p ./dynamic_pager.apple /sbin/dynamic_pager && \
    /bin/chmod +w ./dynamic_pager.apple && \
    /bin/rm -f ./dynamic_pager.apple
[ EOF ]
-----

あとは Leopard と一緒。

vnc_viewer.jpg


RealVNC の4.4.3(vnc-P4_4_3_r16583-x86_win32_viewer)をダウンロードして、MacOS X(Leopard) の画面共有を設定するだけ。


vnc.jpg

MacOS X Leopard - dynamic_pager を骨抜きに をやってみた+α。

[ Makefile ]
----------------------
#
# $Id: Makefile,v 1.1 2008/08/24 21:11:32 dankogai Exp dankogai $
#
# see the URL below!!
#
# http://cestdelamerde.com/archives/22-Killing-Mac-OS-X-Swapping-How-To-Disable-dynamic_pager.html
#

CFLAGS = -no-cpp-precomp -DNO_DIRECT_RPC -framework CoreFoundation \
-framework IOKit -lSystem.B -R -DNO_DIRECT_RPC dynamic_pager.c \
-I/Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/Kernel.framework/Versions/A/Headers \
-I/Developer/SDKs/MacOSX10.4u.sdk/usr/include

all: dynamic_pager

dynamic_pager.c:
curl -O http://cestdelamerde.com/uploads/dynamic_pager.c

i386.out: dynamic_pager.c
cc -arch i386 $(CFLAGS) -o i386.out

ppc.out: dynamic_pager.c
cc -arch ppc $(CFLAGS) -o ppc.out

dynamic_pager: i386.out ppc.out
lipo -create i386.out ppc.out -o dynamic_pager

clean:
rm i386.out ppc.out dynamic_pager

install: dynamic_pager
mv /sbin/dynamic_pager /sbin/dynamic_pager.apple && \
/bin/cp -p /sbin/dynamic_pager.apple . && \
install -m 0555 -o root -g wheel dynamic_pager /sbin

uninstall: dynamic_pager.apple
/bin/chmod +w /sbin/dynamic_pager && \
/bin/rm -f /sbin/dynamic_pager && \
/bin/cp -p ./dynamic_pager.apple /sbin/dynamic_pager && \
/bin/chmod +w ./dynamic_pager.apple && \
/bin/rm -f ./dynamic_pager.apple
[EOF]
----------------------

Xcodeをインストール。
適当なディレクトリーを作成し、Makefileをコピペ。
make
sudo make install

ついでにSwapファイルも移動させます。

sudo mkdir /Volumes/disk2/.vm
sudo ln -s /Volumes/disk2/.vm /private/var/vm

sudo touch /sbin/dynamic_pager_init
sudo vi /sbin/dynamic_pager_init

[ dynamic_pager_init ]
-----------------
#!/bin/bash
#launch Apple's dynamic_pager only when the swap volume is mounted

if [ "x`df -H | grep /Volumes/disk2`" = "x" ]; then
echo "Waiting for Swap volume to mount";
else
echo "Launching dynamic pager on volume Swap";
/sbin/dynamic_pager -F /private/var/vm/swapfile;
fi
[ EOF ]
-----------------

sudo chmod +rx /sbin/dynamic_pager_init

sudo vi /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist

[ com.apple.dynamic_pager.plist ]
----------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.apple.dynamic_pager</string>
<key>OnDemand</key>
<false/>
<key>ProgramArguments</key>
<array>
<!--
- <string>/sbin/dynamic_pager</string>
- <string>-F</string>
- <string>/private/var/vm/swapfile</string>
-->
<string>/sbin/dynamic_pager_init</string>
</array>
</dict>
</plist>
[ EOF ]
----------------------

再起動


このページの先頭へ