Flex

Native extensions for Adobe AIR with iOS - 1 -

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モバイルアプリケーションを作成していきます。

このページの先頭へ