Take Screenshot of Host App Using iOS Share/Action Extensions

Network request from share or action extension ios

You can use URLSession directly from the extension. There is a good tutorial at https://www.raywenderlich.com/158106/urlsession-tutorial-getting-started

let url = URL(...)
let dataTask = defaultSession.dataTask(with: url) { data, response, error in
if let error = error {

// Handle error (error.localizedDescription)
// ...

} else if let data = data,
let response = response as? HTTPURLResponse,
response.statusCode == 200 {

// Handle resonse data
// ...

DispatchQueue.main.async {
// Close extension
// ...
}
}
}

JavaScript won't help in this case. Just make a request to your url and handle the response.

Share Extension to open containing app

Currently there's no way to do this. A share extension cannot open the containing app.

The intended approach for share extensions is that they handle all of the necessary work themselves. Extensions can share code with their containing apps by using custom frameworks, so in most cases that's no problem.

If you want to make data available to your app, you can set up an app group so that you have a shared directory. The extension can write data there, and the app can read it. That won't happen until the next time the user launches the app, though.

Fullscreen in Action extension iOS13

I have found the problem, the NSExtensionActionWantsFullScreenPresentation must be an immediate child of the NSExtension key, and I had it in the wrong place. Now it works!

Open the main app from a iOS Safari Share Extension

I found a solution here. I'm not sure if this is technically ok with Apple, but it works just as I need it to.

@objc func openURL(_ url: URL) {
return
}

func openContainerApp() {
var responder: UIResponder? = self as UIResponder
let selector = #selector(MyViewController.openURL(_:))

while responder != nil {
if responder!.responds(to: selector) && responder != self {
responder!.perform(selector, with: URL(string: "myapp://url")!)
return
}
responder = responder?.next
}
}

Get selected text in Safari and use it in action extension

As Apple explains in their App Extension Programming Guide, you need to include a JavaScript file in the extension to perform any preprocessing. The results of that preprocessing are available via NSExtensionItem in the extension.

A simple example of this file is included in my iOS Extension Demo project at GitHub and looks like this:

var MyPreprocessor = function() {};

MyPreprocessor.prototype = {
run: function(arguments) {
arguments.completionFunction({"URL": document.URL, "pageSource": document.documentElement.outerHTML, "title": document.title, "selection": window.getSelection().toString()});
}
};

var ExtensionPreprocessingJS = new MyPreprocessor;

That simply extracts various details about the current page and passes them to completionFunction. The ExtensionPreprocessingJS var at the end is the hook that the extension framework looks for.

In the extension you can retrieve these values in a dictionary by asking for an item of type kUTTypePropertyList:

for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypePropertyList]) {
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypePropertyList options:nil completionHandler:^(NSDictionary *jsDict, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSDictionary *jsPreprocessingResults = jsDict[NSExtensionJavaScriptPreprocessingResultsKey];
// Continue with data returned from JS...

Rotate image in share extension

First of all it is clear that you have a memory crash. According to App Extension Programming Guide:

Memory limits for running app extensions are significantly lower than the memory limits imposed on a foreground app. On both platforms, the system may aggressively terminate extensions because users want to return to their main goal in the host app.

And from error it is clear that you exceed 120 mb. But you might wonder what is took so much memory.

According to Optimizing Images
Written by Jordan Morgan:

iOS essentially derives its memory hit from an image’s dimensions - whereas the actual file size has much less to do with it.

So if we calculate size or 4032 x 3024 photo it will be... 46mb for 4 bit color and 79mb for 8 bit color. Pretty big, but still less that a limit...

Thing is - you have two copies of your image. One is original and second one - rotated.

To solve this issue you need load only rotated image into memory, without original. This can be done with Image I/O Framework:

extension UIImage {
static func imageWithFixedOrientation(at url: URL) -> UIImage? {
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil }

guard let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? Dictionary<CFString, Any> else { return nil }

guard
let width = imageProperties[kCGImagePropertyPixelWidth] as? CGFloat,
let height = imageProperties[kCGImagePropertyPixelHeight] as? CGFloat
else { return nil }

let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(width, height),
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true
]

guard let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else { return nil }

return UIImage(cgImage: cgImage)
}
}

In sample app:

extension ViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let url = info[.imageURL] as? URL else { return }

let image = UIImage.imageWithFixedOrientation(at: url)
}
}

it reduced memory peaks from 180+mb to just 80mb.



Related Topics



Leave a reply



Submit