Совместное использование расширения в бета-версии IOS8
Я пытаюсь создать расширение общего доступа, используя новые расширения приложений iOS 8. Я попытался получить текущий URL-адрес сайта Safari, чтобы показать его в UILabel. Достаточно просто.
Я работал через официальное руководство по распространению из apple здесь https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Share.html#//apple_ref/doc/uid/TP40014214-CH12-SW1, но некоторые вещи работают не так, как ожидалось. Я знаю, что это только в бета-версии, но, возможно, я просто делаю что-то неправильно.
Вот мой код, чтобы получить URL-адрес сафари внутри расширений ViewController:
-(void)viewDidAppear:(BOOL)animated{
NSExtensionContext *myExtensionContext = [self extensionContext];
NSArray *inputItems = [myExtensionContext inputItems];
NSMutableString* mutableString = [[NSMutableString alloc]init];
for(NSExtensionItem* item in inputItems){
NSMutableString* temp = [NSMutableString stringWithFormat:@"%@, %@, %lu,
%lu - ",item.attributedTitle,[item.attributedContentText string],
(unsigned long)[item.userInfo count],[item.attachments count]];
for(NSString* key in [item.userInfo allKeys]){
NSArray* array = [item.userInfo objectForKey:@"NSExtensionItemAttachmentsKey"];
[temp appendString:[NSString stringWithFormat:@" in array:%[email protected]",[array count]]];
}
[mutableString appendString:temp];
}
self.myLabel.text = mutableString;
}
И это содержимое моего файла Info.plist моего расширения:
<dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>200</integer>
</dict>
</dict>
Когда я посещаю страницу поддержки Apple iPod в Safari и пытаюсь поделиться ею с моим расширением, я получаю следующие значения, но не URL:
item.attributedTitle = (null)
item.attributedContentText = "iPod - Apple Support"
item.userInfo.count = 2 (two keys: NSExtensionAttributedContentTextKey and
NSExtensionItemAttachmentsKey)
item.attachments.count = 0
Массивы внутри объектов словаря всегда пусты.
Когда я делюсь сайтом apple с системным почтовым приложением, URL-адрес отправляется в сообщение. Итак, почему в моем расширении нет URL-адреса?
Ответы
Ответ 1
Ниже вы узнаете, как получить URL. Обратите внимание, что идентификатор типа kUTTypeURL, а аргумент блока - NSURL. Кроме того, plist должен быть правильным, как и мой. Документация отсутствовала и получила помощь от number4 на форумах Apple dev. (вам нужно зарегистрироваться и войти в систему, чтобы увидеть его).
код:
NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
NSItemProvider *itemProvider = item.attachments.firstObject;
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL]) {
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) {
self.urlString = url.absoluteString;
}];
}
Info.plist
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
</dict>
<key>NSExtensionPointName</key>
<string>com.apple.share-services</string>
<key>NSExtensionPointVersion</key>
<string>1.0</string>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
</dict>
Ответ 2
Я решил это для себя. Я пытался использовать Shareing Image.
- (void)didSelectPost {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super -didSelectPost, which will similarly complete the extension context.
// Verify that we have a valid NSExtensionItem
NSExtensionItem *imageItem = [self.extensionContext.inputItems firstObject];
if(!imageItem){
return;
}
// Verify that we have a valid NSItemProvider
NSItemProvider *imageItemProvider = [[imageItem attachments] firstObject];
if(!imageItemProvider){
return;
}
// Look for an image inside the NSItemProvider
if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){
[imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) {
if(image){
NSLog(@"image %@", image);
// do your stuff here...
}
}];
}
// this line should not be here. Cos it called before the block finishes.
// and this is why the console log or any other task won't work inside the block
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
}
Итак, я только что переместил [self.extensionContext completeRequestReturningItems: noil completeHandler: nil]; внутри блока в конце других задач. Окончательная рабочая версия выглядит так (Xcode 6 beta 5 на Mavericks OS X 10.9.4):
- (void)didSelectPost {
// This is called after the user selects Post. Do the upload of contentText and/or NSExtensionContext attachments.
// Inform the host that we're done, so it un-blocks its UI. Note: Alternatively you could call super -didSelectPost, which will similarly complete the extension context.
// Verify that we have a valid NSExtensionItem
NSExtensionItem *imageItem = [self.extensionContext.inputItems firstObject];
if(!imageItem){
return;
}
// Verify that we have a valid NSItemProvider
NSItemProvider *imageItemProvider = [[imageItem attachments] firstObject];
if(!imageItemProvider){
return;
}
// Look for an image inside the NSItemProvider
if([imageItemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage]){
[imageItemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(UIImage *image, NSError *error) {
if(image){
NSLog(@"image %@", image);
// do your stuff here...
// complete and return
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
}
}];
}
// this line should not be here. Cos it called before the block finishes.
// and this is why the console log or any other task won't work inside the block
// [self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
}
Я надеюсь, что он будет работать и для совместного использования URL.
Ответ 3
Контроллер расширения должен принимать протокол NSExtensionRequestHandling
. Один из этих методов протокола:
- (void)beginRequestWithExtensionContext:(NSExtensionContext *)context
Вы должны ждать, пока это будет вызвано, прежде чем пытаться получить NSExtensionContext
. Он даже предоставляет контекст в методе как параметр context
.
Это было указано в этом документе.
Ответ 4
Все эти предыдущие ответы действительно хороши, но я только что столкнулся с этой проблемой в Swift и почувствовал, что было немного некорректно извлекать URL из заданного NSExtensionContext
, особенно в процессе преобразования CFString
в String
, и тот факт, что completionHandler
в loadItemForTypeIdentifier
не выполняется в основном потоке.
import MobileCoreServices
extension NSExtensionContext {
private var kTypeURL:String {
get {
return kUTTypeURL as NSString as String
}
}
func extractURL(completion: ((url:NSURL?) -> Void)?) -> Void {
var processed:Bool = false
for item in self.inputItems ?? [] {
if let item = item as? NSExtensionItem,
let attachments = item.attachments,
let provider = attachments.first as? NSItemProvider
where provider.hasItemConformingToTypeIdentifier(kTypeURL) == true {
provider.loadItemForTypeIdentifier(kTypeURL, options: nil, completionHandler: { (output, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
processed = true
if let url = output as? NSURL {
completion?(url: url)
}
else {
completion?(url: nil)
}
})
})
}
}
// make sure the completion block is called even if no url could be extracted
if (processed == false) {
completion?(url: nil)
}
}
}
Таким образом, теперь вы можете просто использовать его в своем подклассе UIViewController
:
self.extensionContext?.extractURL({ (url) -> Void in
self.urlLabel.text = url?.absoluteString
println(url?.absoluteString)
})
Ответ 5
Другие ответы сложны и неполны. Они работают только в Safari и не работают в Google Chrome. Это работает как в Google Chrome, так и в Safari:
override func viewDidLoad() {
super.viewDidLoad()
for item in extensionContext!.inputItems {
if let attachments = item.attachments {
for itemProvider in attachments! {
itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (object, error) -> Void in
if object != nil {
if let url = object as? NSURL {
print(url.absoluteString) //This is your URL
}
}
})
}
}
}
}
Ответ 6
Вам нужно найти вложение типа kUTTypePropertyList. Сделайте что-то подобное с первым вложением первого элемента расширения в своем расширении:
NSExtensionItem *extensionItem = self.extensionContext.extensionItems.firstObject;
NSItemProvider *itemProvider = self.extensionItem.attachments.firstObject;
[itemProvider loadItemForTypeIdentifier:kUTTypePropertyList options:nil
completionHandler:^(NSDictionary *item, NSError *error) {
// Unpack items from "item" in here
}];
Вам также понадобится настроить JavaScript, чтобы получить все необходимые данные из DOM. Подробнее см. Второй сеанс расширения от WWDC 14.
Ответ 7
let itemProvider = item.attachments?.first as! NSItemProvider
itemProvider.loadItemForTypeIdentifier("public.url", options: nil) { (object, error) -> Void in
println(object)
}
так println:
http://detail.m.tmall.com/item.htm?id=38131345289&spm=a2147.7632989.mainList.5