iOS 从 iOS 11 屏幕截图共享时共享扩展程序崩溃
iOS Share Extension crashes when sharing from iOS 11 Screenshot
我正在开发一个使用照片共享扩展程序的 iOS 应用程序,其中处理图像并触发我们的主要功能。
在 Photo 应用程序的模拟器中,效果很好。我决定从 Photo 的应用程序在设备上 运行,它也很好用,但是当我截图并尝试从 iOS 11 的新 "Quick screenshot" 分享时,扩展程序崩溃了,有什么想法吗?
扩展程序获取图像,将其发送到服务器,获取响应并显示该响应(全部在扩展程序中)。这让我很烦,因为从快速屏幕截图访问时,Messenger 和 Snapchat 共享扩展仍然有效!!
Xcode 9 也没有给我分享扩展的任何日志。还值得注意的是,每次我在设备上重新安装应用程序时,我都需要使用开发者帐户 "trust"。
代码:
// App Group keys
let suiteName = "group.suite.id"
override func viewDidLoad() {
print("Styling views..")
styleViews()
print("Styled views")
print("Adding notifications..")
addNotifications()
print("Added notifications")
print("Fetching image..")
fetchSharedImage()
}
func styleViews(){
// Set up main view
mainView.layer.cornerRadius = 8
mainShadowView.addShadow()
// Set up views and buttons
// Code hidden, applies shadows etc.
// Code hidden, moves constraints of a view
}
func addNotifications(){
// Helps views tell their parent (this view controller) to navigate to another form
NotificationCenter.default.addObserver(forName: NotificationDisplayFetchedLink, object: nil, queue: nil){ notification in
// Handles user info in lambda block
guard let userInfo = notification.userInfo,
let link = userInfo["link"] as? String
else {
print("No userInfo found in notification")
return
}
self.displayResult(with: link)
}
}
func fetchSharedImage(){
// Make sure we have a valid extension item
if let content = extensionContext!.inputItems[0] as? NSExtensionItem {
let contentType = kUTTypeImage as String
// Verify the provider is valid
if let contents = content.attachments as? [NSItemProvider] {
// look for images
for attachment in contents {
if attachment.hasItemConformingToTypeIdentifier(contentType) {
attachment.loadItem(forTypeIdentifier: contentType, options: nil) { data, error in
let url = data as! URL
if let imageData = try? Data(contentsOf: url) {
self.selectedImage = UIImage(data: imageData)
DispatchQueue.main.async {
self.selectedImageView.layer.cornerRadius = 8
self.selectedImageView.image = self.selectedImage
}
self.makeWebRequest()
}
}
}
}
}
}
}
func makeWebRequest(){
let url = URL(string: "url.json")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
// Data is empty
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
guard let dict = json as? [String:Any] else { return }
let item = dict["item"]
guard let itemData = item as? [[String:Any]] else { return }
let link = itemData[0]["url"]
NotificationCenter.default.post(name: NotificationDisplayFetchedLink, object: nil, userInfo: [link: link!])
}
task.resume()
}
编辑:
所以解决方案(正如 Owen Zhao 所说)是 iOS 11 屏幕截图编辑器 return 是一个 UIImage,而像照片这样的应用程序会 return URL。
我优雅地处理这个问题的解决方案是将 UIImage 或 URL 转换为 UIImage 保存到 iOS 临时目录(3 天后删除),然后 returning URL 将该目录中的图像添加到共享扩展。
let url = data as! URL
if let imageData = try? Data(contentsOf: url) {
问题是因为这里的数据不是URL。它是一个 "public.image",尝试转换为 UIImage 而不是 Data。
在 Objective C 中,您可以对作为屏幕截图共享的图像使用以下代码。
具有 .png 扩展名的屏幕截图因此使用 public.png 而不是 public.jpeg
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.png"]){
[itemProvider loadItemForTypeIdentifier:@"public.png" options:nil completionHandler: ^(id<NSSecureCoding> item, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSData *imgData;
if([(NSObject*)item isKindOfClass:[NSURL class]]) {
imgData = [NSData dataWithContentsOfURL:(NSURL*)item];
}
if([(NSObject*)item isKindOfClass:[UIImage class]]) {
imgData = UIImagePNGRepresentation((UIImage*)item);
}
UIImage *image=[UIImage imageWithData:imgData];
});
}];
我正在开发一个使用照片共享扩展程序的 iOS 应用程序,其中处理图像并触发我们的主要功能。
在 Photo 应用程序的模拟器中,效果很好。我决定从 Photo 的应用程序在设备上 运行,它也很好用,但是当我截图并尝试从 iOS 11 的新 "Quick screenshot" 分享时,扩展程序崩溃了,有什么想法吗?
扩展程序获取图像,将其发送到服务器,获取响应并显示该响应(全部在扩展程序中)。这让我很烦,因为从快速屏幕截图访问时,Messenger 和 Snapchat 共享扩展仍然有效!!
Xcode 9 也没有给我分享扩展的任何日志。还值得注意的是,每次我在设备上重新安装应用程序时,我都需要使用开发者帐户 "trust"。
代码:
// App Group keys
let suiteName = "group.suite.id"
override func viewDidLoad() {
print("Styling views..")
styleViews()
print("Styled views")
print("Adding notifications..")
addNotifications()
print("Added notifications")
print("Fetching image..")
fetchSharedImage()
}
func styleViews(){
// Set up main view
mainView.layer.cornerRadius = 8
mainShadowView.addShadow()
// Set up views and buttons
// Code hidden, applies shadows etc.
// Code hidden, moves constraints of a view
}
func addNotifications(){
// Helps views tell their parent (this view controller) to navigate to another form
NotificationCenter.default.addObserver(forName: NotificationDisplayFetchedLink, object: nil, queue: nil){ notification in
// Handles user info in lambda block
guard let userInfo = notification.userInfo,
let link = userInfo["link"] as? String
else {
print("No userInfo found in notification")
return
}
self.displayResult(with: link)
}
}
func fetchSharedImage(){
// Make sure we have a valid extension item
if let content = extensionContext!.inputItems[0] as? NSExtensionItem {
let contentType = kUTTypeImage as String
// Verify the provider is valid
if let contents = content.attachments as? [NSItemProvider] {
// look for images
for attachment in contents {
if attachment.hasItemConformingToTypeIdentifier(contentType) {
attachment.loadItem(forTypeIdentifier: contentType, options: nil) { data, error in
let url = data as! URL
if let imageData = try? Data(contentsOf: url) {
self.selectedImage = UIImage(data: imageData)
DispatchQueue.main.async {
self.selectedImageView.layer.cornerRadius = 8
self.selectedImageView.image = self.selectedImage
}
self.makeWebRequest()
}
}
}
}
}
}
}
func makeWebRequest(){
let url = URL(string: "url.json")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard error == nil else {
return
}
guard let data = data else {
// Data is empty
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! NSDictionary
guard let dict = json as? [String:Any] else { return }
let item = dict["item"]
guard let itemData = item as? [[String:Any]] else { return }
let link = itemData[0]["url"]
NotificationCenter.default.post(name: NotificationDisplayFetchedLink, object: nil, userInfo: [link: link!])
}
task.resume()
}
编辑:
所以解决方案(正如 Owen Zhao 所说)是 iOS 11 屏幕截图编辑器 return 是一个 UIImage,而像照片这样的应用程序会 return URL。
我优雅地处理这个问题的解决方案是将 UIImage 或 URL 转换为 UIImage 保存到 iOS 临时目录(3 天后删除),然后 returning URL 将该目录中的图像添加到共享扩展。
let url = data as! URL
if let imageData = try? Data(contentsOf: url) {
问题是因为这里的数据不是URL。它是一个 "public.image",尝试转换为 UIImage 而不是 Data。
在 Objective C 中,您可以对作为屏幕截图共享的图像使用以下代码。 具有 .png 扩展名的屏幕截图因此使用 public.png 而不是 public.jpeg
if ([itemProvider hasItemConformingToTypeIdentifier:@"public.png"]){
[itemProvider loadItemForTypeIdentifier:@"public.png" options:nil completionHandler: ^(id<NSSecureCoding> item, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSData *imgData;
if([(NSObject*)item isKindOfClass:[NSURL class]]) {
imgData = [NSData dataWithContentsOfURL:(NSURL*)item];
}
if([(NSObject*)item isKindOfClass:[UIImage class]]) {
imgData = UIImagePNGRepresentation((UIImage*)item);
}
UIImage *image=[UIImage imageWithData:imgData];
});
}];