zoukankan      html  css  js  c++  java
  • 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;
    }

     

     

  • 相关阅读:
    Android 音视频同步机制
    FFmpeg命令行工具学习(五):FFmpeg 调整音视频播放速度
    Android框架式编程之RxJava
    Android Gradle 学习笔记(一):Gradle 入门
    FFmpeg开发实战(六):使用 FFmpeg 将YUV数据编码为视频文件
    SDL 开发实战(七): SDL 多线程与锁机制
    JNI实战(四):C 调用 Java
    JNI实战(三):JNI 数据类型映射
    JNI实战(二):Java 调用 C
    JNI实战(一):JNI HelloWorld
  • 原文地址:https://www.cnblogs.com/1oo1/p/4186885.html
Copyright © 2011-2022 走看看