UIActivityViewController的相关用法(一)--URL的发送和接收

UIActivityViewController 是一个能为应用程序提供服务的试图控制器。操作系统已经提供了一些标准服务,诸如 复制内容到剪切板,提交内容到社交网站,通过 email 或 短信发送内容等。应用程序也可以自定义服务。在ios8中系统的一些应用可以直接通过action分享给qq好友和微信好友,是因为腾讯增加了Extension,第三方的app不注册腾讯的开发者是无法使用的。

 UIActivityViewController 的Action分为两类,在UIAction的定义中可以查看到:

UIKIT_EXTERN NSString *const UIActivityTypePostToFacebook     NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToTwitter      NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToWeibo        NS_AVAILABLE_IOS(6_0);    // SinaWeibo
UIKIT_EXTERN NSString *const UIActivityTypeMessage            NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeMail               NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypePrint              NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeCopyToPasteboard   NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeAssignToContact    NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeSaveToCameraRoll   NS_AVAILABLE_IOS(6_0);
UIKIT_EXTERN NSString *const UIActivityTypeAddToReadingList   NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToFlickr       NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToVimeo        NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypePostToTencentWeibo NS_AVAILABLE_IOS(7_0);
UIKIT_EXTERN NSString *const UIActivityTypeAirDrop            NS_AVAILABLE_IOS(7_0);

typedef NS_ENUM(NSInteger, UIActivityCategory) {
    UIActivityCategoryAction,
    UIActivityCategoryShare,
} NS_ENUM_AVAILABLE_IOS(7_0);

 

应用程序要复制配置、呈现和消除 UIActivityViewController。UIActivityViewContoller 的配置需要明确指出控制器要表现出的数据对象。

下面的代码源自于苹果官方提供的AirDropSample项目,按照本人理解的顺序解析,每个人理解的角度不一样,有偏差请以官方代码和释义为准。

一:通过UIActivityViewController发送/接收URL(文本等同之)

发送:用一个URLViewController来管理(

如果app用URL发送元数据,应该创建一个包含该url的容器类,此类必须要实现 UIActivityItemSource 协议。

)

#import <UIKit/UIKit.h>

@interface UrlViewController : UIViewController
@end

#import "UrlViewController.h"
#import "Utilities.h"
#import "UrlContainer.h"

@interface UrlViewController ()<UITextFieldDelegate>
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (strong, nonatomic) UrlContainer *urlContainer;

@property (strong, nonatomic) UIPopoverController *popOverController;

@end

@implementation UrlViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 加载收到的url, 如果没有收到的url返回nil
    NSURL *url = [Utilities loadUrl];
    if (!url) {
        url = [NSURL URLWithString:@"hsun://test/one/two?key1=value1"];
    }
//    NSLog(@"host:%@, user:%@, path:%@, fragment:%@, parameterString:%@, query:%@, relativePath:%@", url.host, url.user, url.path, url.fragment, url.parameterString, url.query, url.relativePath);
    // 初始化item容器
    self.urlContainer = [[UrlContainer alloc] initWithUrl:url];
    // 显示容器中的URL内容
    self.textField.text = [self stringWithoutURLScheme:self.urlContainer.url];
}

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    // 为控制器注册通知,接收到URL, 保存窗口将要呈现
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadUrl) name:@"ReceiveURLViewController" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveWindowWillAppear) name:@"SaveWindowWillAppear" object:nil];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    // view 消失时移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"ReceiveURLViewController" object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"SaveWindowWillAppear" object:nil];
}

- (IBAction)share:(id)sender {
    // 用实现了 UIActivityItemSource协议的item容器初始化,容器类的定义在下面
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[self.urlContainer] applicationActivities:nil];
    
    /***
     action 分为两种 :
     UIActivityCategoryAction,
     UIActivityCategoryShare
     如果有不想展示的Share 或者 Action,可以通过如下实现
     activityViewController.excludedActivityTypes = @[UIActivityTypePrint];
   选择Action即可发送容器内的URL了,至此发送URL(文本)完成 **
*/ // iphone 直接呈现 if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) { [self presentViewController:activityViewController animated:YES completion:nil]; } else // ipad 需要用PopOver { if([self.popOverController isPopoverVisible]) { [self.popOverController dismissPopoverAnimated:YES]; } else { self.popOverController = [[UIPopoverController alloc] initWithContentViewController:activityViewController]; [self.popOverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES]; } } } #pragma mark - UITextFieldDelegate -(BOOL)textFieldShouldReturn:(UITextField *)textField { [self.textField resignFirstResponder]; return YES; } -(void)textFieldDidEndEditing:(UITextField *)textField { // 输入的如果不同于url容器中的内容,重新为其赋值 if(![self.textField.text isEqualToString:[self stringWithoutURLScheme:self.urlContainer.url]]) { NSString *urlString = [NSString stringWithFormat:@"hsun://%@", self.textField.text]; self.urlContainer.url = [NSURL URLWithString:urlString]; } } #pragma mark - String of url without scheme -(NSString *)stringWithoutURLScheme:(NSURL*)url { NSString *scheme = [[url scheme] stringByAppendingString:@"://"]; // 从scheme之后截取 return [[url absoluteString] substringFromIndex:scheme.length]; } #pragma mark - Handle received notifications -(void)reloadUrl { // 收到通知后加载收到的url NSURL *receivedUrl = [Utilities loadUrl]; if(receivedUrl) { self.urlContainer.url = receivedUrl; self.textField.text = [self stringWithoutURLScheme:receivedUrl]; } } -(void)saveWindowWillAppear { // 处理窗口将要呈现的通知 [self.textField resignFirstResponder]; } @end

 

关于实现UIActivityItemSource的URL(文本)容器类,

 

#import <Foundation/Foundation.h>

@interface UrlContainer : NSObject<UIActivityItemSource>

@property (nonatomic, strong) NSURL *url;
-(instancetype)initWithUrl:(NSURL*)url;

@end

#import "UrlContainer.h"
#import "UIImage+resize.h"

@implementation UrlContainer

-(instancetype)initWithUrl:(NSURL *)url
{
    self = [super init];
    if(self)
    {
        self.url = url;
    }
    return self;
}

#pragma mark - UIActivityItemSource
-(id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
    // 占位,将要返回的类型
    return self.url;
}

-(id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
    // 直接返回容器的url
    return self.url;
}
-(UIImage*)activityViewController:(UIActivityViewController *)activityViewController thumbnailImageForActivityType:(NSString *)activityType suggestedSize:(CGSize)size
{
    // 为item提供缩略图,大小为建议的大小
    // 用自定义的UIImage的Category resize 类方法处理图片为缩略图
    return [UIImage imageWithImage:[UIImage imageNamed:@"Beads.png"] scaledToFitToSize:size];
}
@end

自定义的UIImage+resize

#import <UIKit/UIKit.h>

@interface UIImage (resize)

+(UIImage*)imageWithImage:(UIImage*)image scaledToFitToSize:(CGSize)size;
+(UIImage*)imageWithImage:(UIImage*)image scaledToFillToSize:(CGSize)size;

@end

#import "UIImage+resize.h"

@implementation UIImage (resize)

// 根据尺寸和矩形重绘图片
+(UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)size inRect:(CGRect)rect
{
    if ([UIScreen mainScreen].scale == 2.0) {
        UIGraphicsBeginImageContextWithOptions(size, YES, 2.0);
    }
    else
    {
        UIGraphicsBeginImageContext(size);
    }
    [image drawInRect:rect];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

+(UIImage*)imageWithImage:(UIImage *)image scaledToFitToSize:(CGSize)size
{
    // 如果图片原尺寸已经小于要Scaled尺寸,不作处理
    if(image.size.height < size.height && image.size.width < size.width)
    {
        return [image copy];
    }
    
    // 根据缩放后的宽高,得到缩放比例
    CGFloat widthScaled = size.width / image.size.width;
    CGFloat heigtScaled = size.height / image.size.height;
    CGFloat scaledFactor = widthScaled > heigtScaled ? heigtScaled : widthScaled;
    
    // 缩放图片的尺寸
    CGSize scaledSize = CGSizeMake(image.size.width * scaledFactor, image.size.height * scaledFactor);
    return [UIImage imageWithImage:image scaledToSize:scaledSize inRect:CGRectMake(0.0, 0.0, scaledSize.width, scaledSize.height)];
}

+(UIImage*)imageWithImage:(UIImage *)image scaledToFillToSize:(CGSize)size
{
    // 如果图片原尺寸已经小于要Scaled尺寸,不作处理
    if(image.size.height < size.height && image.size.width < size.width)
    {
        return [image copy];
    }
    
    // 根据缩放后的宽高,得到缩放比例
    CGFloat widthScaled = size.width / image.size.width;
    CGFloat heigtScaled = size.height / image.size.height;
    CGFloat scaledFactor = widthScaled > heigtScaled ? heigtScaled : widthScaled;
    // 缩放图片的尺寸
    CGSize scaledSize = CGSizeMake(image.size.width * scaledFactor, image.size.height * scaledFactor);
    
    CGPoint scaledPoint;
    widthScaled > heigtScaled ? (scaledPoint.y = (size.height - scaledSize.height)/2) : (scaledPoint.x = (size.width - scaledSize.height)/2);
    
    return [UIImage imageWithImage:image scaledToSize:size inRect:CGRectMake(scaledPoint.x, scaledPoint.y, scaledSize.width, scaledSize.height)];
}

@end

 接收:通过AirDrop接收URL(

要想接收一个自定义了scheme的URL,app需要注册为能接收这个scheme。在项目的Target下的Info节点,有URL Types,在此注册, 或者用代码注册,详细可参考此链接http://www.cocoachina.com/industry/20140522/8514.html

AirDrop接收到内容后会调用 UIApplication 的委托方法 application:openURL:sourceApplication:annotation,关于此方法的详细可以查看文档;

#import "AppDelegate.h"
#import "RootTableViewController.h"
#import "Utilities.h"

@interface AppDelegate ()

@property (nonatomic, strong) UINavigationController *navController;
@property (nonatomic, strong) RootTableViewController *rootTableViewController;
@property (nonatomic, strong) UIWindow *saveReceivedWindow;

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    self.navController = [[UIStoryboard storyboardWithName:@"Main.stroyboard" bundle:nil] instantiateInitialViewController];
    if(self.navController)
    {
        self.rootTableViewController = [[self.navController viewControllers] firstObject];
    }
    
    return YES;
}

-(void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"%@", NSStringFromSelector(_cmd));
}

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
    if (url) {
        //在此处理接收到的url
        // 需要校验收到的是否是app需要的。saveReceivedWindow是为了接收数据类型而设的变量
        if ([url.scheme isEqualToString:@"hsun"]) {
            // 保存url到文档中
            [Utilities saveUrl:url];
            // 广播收到URL的通知,如果UrlViewController处于显示状态则会收到此通知,然后重新从文档中加载新保存的url内容
            [[NSNotificationCenter defaultCenter] postNotificationName:@"ReceiveURLViewController" object:nil];
            
            //如果UrlViewController没有显示,调用根控制器显示
            if ([self.navController.visibleViewController isEqual:self.rootTableViewController] && !self.saveReceivedWindow) {
                [self.rootTableViewController showUrlViewController];
            }
        }
    }
    return YES;
}

 

posted @ 2014-12-25 15:06  1oo1  阅读(988)  评论(0编辑  收藏  举报