UIActivityViewController的相关用法(二)--NSData的发送和接收

通过AirDrop发送一张图片或者一个文件,需要序列化实现了NSActivityItemSource的容器类实例,以NSData的数据格式传输。app发送/接收自定义的类型实例,还需要创建一个自定义的UTI,需要在Targets的info中添加两个节点:Document Types 和 Exported Type UTIs;

1、Document Types:

app注册此字段后可以接受自定义的UTI,同时这个字段也可以用来接收其他标准的UTI文件类型。

2、Exported Type UTIs:通过此字段向系统注册此app的自定义UTI。

发送被序列号容器类需要有两个选择:

1、把对象写入到遵循自定义UTI的文件中,把文件的路径作为url传入到UIActivityVIewController中。

2、序列化对象为NSData对象,把数据(NSData)对象传到UIActivityViewController,UIActivityViewController 会调用UIActivityItemSource的协议方法activityViewController:dataTypeIdentifierForActivityItemSource来确定自定义的UTI(将要使用的就是这种)。

当AirDrop接收到一个自定义UTI的文件时,它会寻找在系统中注册过改UTI的app,如果有多个app注册过改UTI,会显示一个选择列表。选中app后,该app的UIApplication的委托方法 application:openURL:sourceApplication:annotation 会被调用,在这个方法中处理接收到的文件,接收到的文件被保存在Document/Inbox文件夹中,app只有读取和删除的权限,建议copy到自定义的路径中,以便做增删改的操作。

发送:

- (IBAction)shareAction:(id)sender {
    // 传入的虽然时item的容器类实例,实际UIActivityViewController会调用UIActivityItemSource协议方法把该实例序列化为NSData
    // 可以从容器类 Profile 中看到明细。
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[self.profile] applicationActivities:nil];
    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
        [self presentViewController:activityViewController animated:YES completion:nil];
    }
    else
    {
        if(self.actionPopoverController.isPopoverVisible)
        {
            [self.actionPopoverController dismissPopoverAnimated:YES];
        }
        else
        {
            self.actionPopoverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController];
            [self.actionPopoverController presentPopoverFromBarButtonItem:self.actionItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
        }
    }
}

容器类Profile:

#import <Foundation/Foundation.h>

@interface Profile : NSObject<NSSecureCoding, UIActivityItemSource>

@property (nonatomic, copy) NSString *name;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImage *thumbnailImage;
@property (nonatomic, copy) NSString *fileName;
@property (nonatomic, assign) NSInteger imageContentMode;

-(instancetype)initWithName:(NSString*)name image:(UIImage*)image;

@end

#import "Profile.h"
#import "UIImage+resize.h"
#import "Utilities.h"

@implementation Profile

// 初始化Profile的name和image
-(instancetype)initWithName:(NSString *)name image:(UIImage *)image
{
    self = [super init];
    if(self)
    {
        _name = name;
        // 设置图片的尺寸
        _image = [UIImage imageWithImage:image scaledToFitToSize:CGSizeMake(560, 470)];
    }
    return self;
}

// 属性fileName如果不存在,构造一个随机的名字
-(NSString*)fileName
{
    if (_fileName) {
        return _fileName;
    }
    
    _fileName = [NSString stringWithFormat:@"profile-%@.customprofile", [[[NSUUID UUID] UUIDString] substringWithRange:NSMakeRange(24, 12)]];
    return _fileName;
}

// 设置image的同时设置thumbnailImage
-(void)setImage:(UIImage *)image
{
    _image = [UIImage imageWithImage:image scaledToFitToSize:CGSizeMake(560, 470)];
    _thumbnailImage = [UIImage imageWithImage:image scaledToFitToSize:CGSizeMake(44, 44)];
}

// thumbnailImage不存在,现场构造
-(UIImage*)thumbnailImage
{
    if(_thumbnailImage)
        return _thumbnailImage;
    
    _thumbnailImage = [UIImage imageWithImage:_image scaledToFitToSize:CGSizeMake(44, 44)];
    return _thumbnailImage;
}

#pragma mark - NSCoding
// NSSecureCoding 继承自NSCoding,所以必须实现NSCoding,同时该类的实例能够序列化为NSData数据类型以便传输
-(void)encodeWithCoder:(NSCoder *)aCoder
{
    [aCoder encodeObject:_name forKey:@"name"];
    [aCoder encodeObject:_image forKey:@"image"];
    [aCoder encodeObject:@(_imageContentMode) forKey:@"imageContentMode"];
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
    Profile *profile = nil;
    NSString *name = [aDecoder decodeObjectOfClass:[NSString class] forKey:@"name"];
    UIImage *image = [aDecoder decodeObjectOfClass:[UIImage class] forKey:@"image"];
    NSNumber *imageContentMode = [aDecoder decodeObjectOfClass:[NSNumber class] forKey:@"imageContentMode"];
    
    if(name && image && imageContentMode)
    {
        profile = [[Profile alloc] initWithName:name image:image];
        profile.imageContentMode = imageContentMode.integerValue;
    }
    return profile;
}

#pragma mark - NSSecureCoding
+(BOOL)supportsSecureCoding
{
    return YES;
}

#pragma mark - UIActivityItemSource
-(id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
    // 该类作为数据容器,最终是以NSData的数据类型发送的
    return [NSData data];
}
-(id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
    // 被序列化后的该对象作为item发送
    return [Utilities securelyArchiveRootObject:self];
}
-(NSString*)activityViewController:(UIActivityViewController *)activityViewController dataTypeIdentifierForActivityType:(NSString *)activityType
{
    return @"com.hsun.customProfileUTI.customProfile";
}

-(UIImage*)activityViewController:(UIActivityViewController *)activityViewController thumbnailImageForActivityType:(NSString *)activityType suggestedSize:(CGSize)size
{
    UIImage *scaledImage;
    if (self.imageContentMode == UIViewContentModeScaleToFill) {
        scaledImage = [UIImage imageWithImage:self.image scaledToFillToSize:size];
    }
    else
    {
        scaledImage = [UIImage imageWithImage:self.image scaledToFitToSize:size];
    }
    return scaledImage;
}
@end

 当同意接收AirDrop发送的数据后,若设备已经注册了该UTI的app,会用此app打开(多个的话会让选择),调用app的应用委托方法来处理接收的数据:

// 处理接收的数据
-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    if (url) {
        //当同意接受AirDrop发送的文件后,AirDrop会自动查询注册了UTI的app,找到之后就把文件放到
        // Document/Inbox 文件夹下面(不存在该UTI的app则会自动跳转到ItuneStore搜做符合此UTI的app)
        // 读取接收到的文件,并处理(同接收URL处理的不同之处就是这里,从inbox中读取接收到的文件,这个文件是序列化后的数据文件)
        NSString *path = [url path];
        Profile *profile = [Utilities securelyUnarchiveProfileWithPath:path];
        if(profile)
        {
            //用接收到的数据做想做的事情。。。
        }
        
        // 删除放在 Document/Inbox 下接收到的文件
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
    }
    return YES;
}

 

 

 

 

posted @ 2014-12-26 15:32  1oo1  阅读(1997)  评论(0编辑  收藏  举报