曾静的博客

但行好事,莫问前程.

嗨,我是曾静 (@devzeng),目前暂居深圳。


这是我用来记录平日学习笔记的地方,欢迎您的访问.

iOS8中的Safari Action Extension

扩展(Extension)是iOS8中引入的一个非常重要的新特性。扩展让app之间的数据交互成为可能。用户可以在app中使用其他应用提供的功能,而无需离开当前的应用。前面介绍过关于Today Widget的使用,本文介绍Action Extension在iOS8中的开发。

201111194125034.png

###创建Action Extension

1、使用Xcode6创建一个iOS工程,菜单栏File->New->Target出现下面的可选项,选择Action Extension:

action_extension_01.png

2、配置Extension的Product Name等内容。

action_extension_02.png

###配置Action Extension

1、默认Action Extension中的布局使用StoryBoard,如果不想使用StoryBoard布局将Info.plist中的如下配置:

<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>

改为下面的配置:

<key>NSExtensionPrincipalClass</key>
<string>ActionViewController</string>

说明:

插件在UI上以UIViewController模式存在,被parentViewController(Host App)以模态窗口形式弹出(present as modal viewController)。插件工程在Info.plist的NSExtension中通过NSExtensionMainStoryboard指定UI视图入口。当然,如果不想使用storyboard,也可以使用NSExtensionPrincipalClass指定自定义UIViewController子类名(也可以封装到UINavigationController)。

2、NSExtensionActivationRule定义了当前的扩展支持的数据类型及数据项个数,例如设置只支持图片格式和视频格式的数据,并且最多不超过10张图片和1个视频。

<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<string>1</string>

3、NSExtensionJavaScriptPreprocessingFile用于配置与脚本交互的JS脚本文件的名字。为了告知Safari你的应用扩展中包含一个JavaScript文件,你需要在应用扩展的Info.plist文件中,向NSExtensionAttributes字典添加NSExtensionJavaScriptPreprocessingFile关键字来指明你的JavaScript文件。这个关键字的值就是你希望当你的应用扩展运行前,Safari要加载的JavaScript文件的名称。比如:

<key>NSExtensionJavaScriptPreprocessingFile</key>
<string>ScreenShotJavaScript</string>

4、NSExtensionPointIdentifier用于表示扩展点,每一个扩展点拥有一个唯一的名字。

<key>NSExtensionPointIdentifier</key>
<string>com.apple.ui-services</string>

###示例程序

实现一个网页截屏的功能,用户在Safari中的Action选择指定的动作,然后将网页的内容以图片的形式保存下来,类似于Screenshot.

action_extension_03.png

1、将UIWebView进行截屏

- (UIImage *)screenshot
{
    CGSize boundsSize = self.bounds.size;
    CGFloat boundsWidth = self.bounds.size.width;
    CGFloat boundsHeight = self.bounds.size.height;
    
    CGPoint offset = self.scrollView.contentOffset;
    [self.scrollView setContentOffset:CGPointMake(0, 0)];
    
    CGFloat contentHeight = self.scrollView.contentSize.height;
    NSMutableArray *images = [NSMutableArray array];
    while (contentHeight > 0) {
        UIGraphicsBeginImageContext(boundsSize);
        [self.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        [images addObject:image];
        
        CGFloat offsetY = self.scrollView.contentOffset.y;
        [self.scrollView setContentOffset:CGPointMake(0, offsetY + boundsHeight)];
        contentHeight -= boundsHeight;
    }
    [self.scrollView setContentOffset:offset];
    
    UIGraphicsBeginImageContext(self.scrollView.contentSize);
    [images enumerateObjectsUsingBlock:^(UIImage *image, NSUInteger idx, BOOL *stop) {
        [image drawInRect:CGRectMake(0, boundsHeight * idx, boundsWidth, boundsHeight)];
    }];
    UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return fullImage;
}

2、在ActionViewController中获取网页的URL地址

for (NSExtensionItem *item in self.extensionContext.inputItems) {
	for (NSItemProvider *itemProvider in item.attachments) {
		__weak UIWebView *webView = self.myWebView;
		NSString *identifier = (NSString *)kUTTypeURL;
		BOOL status = [itemProvider hasItemConformingToTypeIdentifier:identifier];
		if(status){
			[itemProvider loadItemForTypeIdentifier:identifier options:nil completionHandler:^(NSURL *item, NSError *error) {
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [webView loadRequest:[NSURLRequest requestWithURL:item]];
                    }];
             }];		
             break;
        }
    }
}

###参考资料

1、《将UIWebView显示的内容转为图片和PDF》

2、《如何给UITableView 或 UIScrollView 的content 做截图》

3、《App Extension Programming Guide》

4、《iOS8扩展插件开发配置》

最近的文章

iOS开发中善用日志记录工具

在iOS开发中经常需要靠记录日志来调试应用程序,最常见的做法是使用NSLog来输出相关的信息。大量的使用NSLog存在一定的弊端,将设备连接到电脑,打开XCode中的Device->Console,就可以从console查看到每条日志信息(或者是使用iTools的实时日志,推荐使用)。试想如果将很多核心的算法或者是信息都通过NSLog打印到控制台上,那么很有可能会被其他人获取到相关信息造成很多安全隐患,另外这样的应用也极有可能被Apple拒绝审核通过。###使用宏来处理常用的做法是在...…

iOS继续阅读
更早的文章

iOS中ARC下block的循环引用

在iOS4.2时,Apple推出ARC的内存管理机制。这是一种编译期的内存管理方式,在编译期间,编译器会判断对象的使用情况,并适当的加上retain和release,使得对象的内存被合理的管理。所以,从本质上说ARC和MRC在本质上是一样的,都是通过引用计数的内存管理方式。使用ARC虽然可以简化内存管理,但是ARC并不是万能的,有些情况程序为了能够正常运行,会隐式地持有或者复制对象,如果不加以注意,便会造成内存泄露。在ARC下,当block获取到外部变量时,由于编译器无法预测获取到的变量何...…

iOS继续阅读