Mac到蓝牙设备文件传输,简单示例?

nor*_*gen 5 macos cocoa bluetooth objective-c iobluetooth

我花了两天的时间在谷歌上搜索并阅读了《蓝牙编程指南》,同时试图拼凑一个小型Mac应用程序,该应用程序将从放置文件夹中检索图像并将任何新文件通过蓝牙发送到预定的设备。似乎没有很多好的例子。

我现在可以生成蓝牙服务浏览器并选择设备及其OBEX服务,建立服务并创建连接,但是接下来什么也没有发生。谁能指出我的方向/向我展示一个简单的例子?

随附AppDelegate源代码。谢谢阅读!

#import“ AppDelegate.h”

@implementation AppDelegate

-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    IOBluetoothServiceBrowserController *浏览器= [IOBluetoothServiceBrowserController serviceBrowserController:0];
    [浏览器runModal];

    // IOBluetoothSDPServiceRecord
    IOBluetoothSDPServiceRecord * result = [[浏览器getResults] objectAtIndex:0];
    [自我描述:结果];

    如果([[result.device.name substringToIndex:8] isEqualToString:@“ Polaroid”]){
        打印机= result.device;
        serviceRecord =结果;
        [self testPrint];
    }
    其他{
        NSLog(@“%@不是有效的设备”,result.device.name);
    }
}

-(void)testPrint {
     currentFilePath = @“ / Users / oyvind / Desktop / _DSC8797.jpg”;
    [self sendFile:currentFilePath];
}

-(void)sendFile:(NSString *)filePath {
    IOBluetoothOBEXSession * obexSession = [[IOBluetoothOBEXSession alloc] initWithSDPServiceRecord:serviceRecord];

    if(obexSession!= nil)
    {
        NSLog(@“已建立OBEX会话”);

        OBEXFileTransferServices * fst = [OBEXFileTransferServices withOBEXSession:obexSession];
        OBEXDelegate * obxd = [[[OBEXDelegate alloc] init];
        [obxd setFile:filePath];
        [fst setDelegate:obxd];

        OBEXError cnctResult = [fst connectToObjectPushService];

        if(cnctResult!= kIOReturnSuccess){
            NSLog(@“创建连接时出错”);
            返回;
        }
        其他{
            NSLog(@“ OBEX会话已创建。正在发送文件:%@”,filePath);
            [fst sendFile:filePath];
            [打印机openConnection];
        }
    }
    其他{
        NSLog(@“创建OBEX会话时出错”);
        NSLog(@“发送文件时出错”);
    }
}

@结束

nor*_*gen 2

好的; 这就是最终成为该功能的核心部分的内容。我制作的应用程序是一种用于宝丽莱即时打印机的打印服务器,它仅通过对象推送接受图像。

首先,确保监视文件夹存在。

/*

    Looks for a directory named PolaroidWatchFolder in the user's desktop directory
    and creates it if it does not exist.

 */

- (void) ensureWatchedFolderExists {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *url = [NSURL URLWithString:@"PolaroidWatchFolder" relativeToURL:[[fileManager URLsForDirectory:NSDesktopDirectory inDomains:NSUserDomainMask] objectAtIndex:0]];
    BOOL isDir;
    if ([fileManager fileExistsAtPath:[url path] isDirectory:&isDir] && isDir) {
        [self log:[NSString stringWithFormat:@"Watched folder exists at %@", [url absoluteURL]]];
        watchFolderPath = url;
    }
    else {
        NSError *theError = nil;
        if (![fileManager createDirectoryAtURL:url withIntermediateDirectories:NO attributes:nil error:&theError]) {
            [self log:[NSString stringWithFormat:@"Watched folder could not be created at %@", [url absoluteURL]]];
        }
        else {
            watchFolderPath = url;
            [self log:[NSString stringWithFormat:@"Watched folder created at %@", [url absoluteURL]]];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后扫描可用的打印机:

/*

    Loops through all paired Bluetooth devices and retrieves OBEX Object Push service records
    for each device who's name starts with "Polaroid".

 */

- (void) findPairedDevices {
    NSArray *pairedDevices = [IOBluetoothDevice pairedDevices];
    devicesTested = [NSMutableArray arrayWithCapacity:0];
    for (IOBluetoothDevice *device in pairedDevices)
    {
        if ([self deviceQualifiesForAddOrRenew:device.name])
        {
            BluetoothPushDevice *pushDevice = [[BluetoothPushDevice new] initWithDevice:device];
            if (pushDevice != nil)
            {
                [availableDevices addObject:pushDevice];
                [pushDevice testConnection];                
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后一个函数调用是对 BluetoothPushDevice 的内置方法的调用,以测试连接。这是响应的委托处理程序:

- (void) deviceStatusHandler: (NSNotification *)notification {
    BluetoothPushDevice *device = [notification object];
    NSString *status = [[notification userInfo] objectForKey:@"message"];

    if ([devicesTested count] < [availableDevices count] && ![devicesTested containsObject:device.name]) {
        [devicesTested addObject:device.name];
    }
}
Run Code Online (Sandbox Code Playgroud)

服务器启动后,此方法将运行以响应计时器滴答或手动扫描:

- (void) checkWatchedFolder {
    NSError *error = nil;
    NSArray *properties = [NSArray arrayWithObjects: NSURLLocalizedNameKey, NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey, nil];

    NSArray *files = [[NSFileManager defaultManager]
                      contentsOfDirectoryAtURL:watchFolderPath
                      includingPropertiesForKeys:properties
                      options:(NSDirectoryEnumerationSkipsHiddenFiles)
                      error:&error];

    if (files == nil) {
        [self log:@"Error reading watched folder"];
        return;
    }

    if ([files count] > 0) {
        int newFileCount = 0;

        for (NSURL *url in files) {
            if (![filesInTransit containsObject:[url path]]) {
                NSLog(@"New file: %@", [url lastPathComponent]);
                [self sendFile:[url path]];
                newFileCount++;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当发现新文件时,ww 首先需要找到一个不忙于接收文件的设备来打印它:

/*

 Loops through all discovered device service records and returns the a new OBEX session for
 the first it finds that is not connected (meaning it is not currently in use, connections are
 ad-hoc per print).

 */

- (BluetoothPushDevice*) getIdleDevice {
    for (BluetoothPushDevice *device in availableDevices) {
        if ([device.status isEqualToString:kBluetoothDeviceStatusReady]) {
            return device;
        }
    }
    return nil;
}
Run Code Online (Sandbox Code Playgroud)

然后使用此方法发送文件:

- (void) sendFile:(NSString *)filePath {
    BluetoothPushDevice *device = [self getIdleDevice];
        if( device != nil ) {
        NSLog(@"%@ is available", device.name);
        if ([device sendFile:filePath]) {
            [self log:[NSString stringWithFormat:@"Sending file: %@", filePath]];
            [filesInTransit addObject:filePath];
        }
        else {
            [self log:[NSString stringWithFormat:@"Error sending file: %@", filePath]];
        }
    }
    else {
        NSLog(@"No idle devices");
    }
}
Run Code Online (Sandbox Code Playgroud)

传输完成后,将调用此委托方法:

/*

    Responds to BluetoothPushDevice's TransferComplete notification

 */

- (void) transferStatusHandler: (NSNotification *) notification {
    NSString *status = [[notification userInfo] objectForKey:@"message"];
    NSString *file = ((BluetoothPushDevice*)[notification object]).file;

    if ([status isEqualToString:kBluetoothTransferStatusComplete]) {
        if ([filesInTransit containsObject:file]) {
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSError *error = nil;
            [fileManager removeItemAtPath:file error:&error];
            if (error != nil) {
                [self log:[NSString stringWithFormat:@"**ERROR** File %@ could not be deleted (%@)", file, error.description]];
            }

            [self log:[NSString stringWithFormat:@"File deleted: %@", file]];
            [filesInTransit removeObject:file];
        }
        else {
            [self log:[NSString stringWithFormat:@"**ERROR** filesInTransit array does not contain file %@", file]];
        }
    }

    [self updateDeviceStatusDisplay];
}
Run Code Online (Sandbox Code Playgroud)

我希望这可以帮助别人!