I am trying to make UIActivityViewController stop showing localized contents such as translated apps and etc... to make it displays only in English. My app contains two localization English and Arabic.
I have added Localized resources can be mixed = NO to the info plist file but no success. Is there any way to stop localization for UIActivityViewController? Here is my codes:
struct ActivityViewController: UIViewControllerRepresentable {
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
print("activityItems=\(activityItems)")
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
controller.view.semanticContentAttribute = .forceLeftToRight
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}
Related
In iOS 16, when can use ShareLink to present a share sheet. Is there a way to get notified when user swipe down or close this view? Need to do something after the share sheet is dismissed.
I was struggling with this too. As far as I can tell, ShareLink doesn't yet have a way to run code on dismiss. What worked very well for me was adapting UIActivityViewController for SwiftUI, and then presenting the share view in a sheet.
struct ActivityViewController: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]? = nil
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}
Usage:
Button(action: {
presentShareSheet = true
}) {
Text("Share Link")
}
.sheet(isPresented: $presentShareSheet, onDismiss: {
// Code to run on dismiss
}) {
ActivityViewController(activityItems: ["Check out this link!", URL(string: "https://www.google.com")!])
}
I am using UIActivityViewController to share text to Outlook, everything is working fine except for two things, one I can't set a subject line and two I cant set a title of that I am sharing, my text is html table and it is currently shown the first part of it in my implementation (see screenshot) although I'd like to show a preview title.
Is there a way to set the title and a way to set the subject?
Here is my code:
let activityViewController = UIActivityViewController(activityItems : [htmlString], applicationActivities: nil)
activityViewController.popoverPresentationController?.barButtonItem = self.shareButton
self.present(activityViewController, animated: true, completion: nil)
I have tried to set the subject like so:
activityViewController.setValue("This is my subject", forKey: "subject")
But it didn't work
What am I doing wrong?
Here is the screenshot of the title I was talking about:
But it didn't work
Whatever view controller triggered the sharing should conform to UIActivityItemSource protocol in order to setup: preview title, email subject and as well the content of the email.
You can try out your self this example which triggers sharing on a button tap:
class ViewController: UIViewController, UIActivityItemSource {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func sharePressed(_ sender: Any) {
let item = [self, "Preview Title"] as [Any]
let activityViewController = UIActivityViewController(activityItems: item, applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)
}
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return ""
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? {
return "<html><body><p style=\"background-color: red;\">Email body message with red background</p></body></html>"
}
func activityViewController(_ activityViewController: UIActivityViewController, subjectForActivityType activityType: UIActivity.ActivityType?) -> String {
return "Email Subject"
}
}
To have this expected output:
Some apps like Outlook and Gmail in different iOS Versions (iOS 11, iOS 12..) behave differently: some take the first line of the body and set it as the Subject. Just be sure to test it out for the iOS version you are targeting and the app that you want to target the sharing functionality to behave correctly. You could also set multiple itemForActivityType to target logic for different apps when sharing.
I have a view controller containing a UIWebView and a toolbar with an action/share button. This initializes and presents a UIActivityViewController object. Depending on whether I supply the activityItems parameter with either the web view's URL or the URL's corresponding absoluteString, different actions are offered, but the Print option is never shown (nor offered in the "more" section).
I do know how to print the web view contents explicitly using UIPrintInfo and UIPrintInteractionController, but that would be a separate toolbar button whereas I want to simply include the system's Print option into the activity button row. I assume printing a web view does not need any explicit coding.
What can I do?
You can create Custom Activity For UIActivityCotnroller like this,
import UIKit
protocol CustomActivityDelegate : NSObjectProtocol
{
func performActionCompletion(actvity: CustomActivity)
}
class CustomActivity: UIActivity {
var delegate: CustomActivityDelegate?
override class var activityCategory: UIActivityCategory {
return .action
}
override var activityType: UIActivityType? {
guard let bundleId = Bundle.main.bundleIdentifier else {return nil}
return UIActivityType(rawValue: bundleId + "\(self.classForCoder)")
}
override var activityTitle: String? {
return "You title"
}
override var activityImage: UIImage? {
return <Your activity image >
}
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
return true
}
override func prepare(withActivityItems activityItems: [Any]) {
//
}
override func perform() {
self.delegate?.performActionCompletion(actvity: self)
activityDidFinish(true)
}
}
You can initialize this activity some thing like this
let customActivity = CustomActivity()
customActivity.delegate = self
And you can add this custom activity while preparing UIActivityController
let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: [customActivity], applicationActivities: nil)
and you will also need to implement the call back method
func performActionCompletion(actvity: CustomActivity)
{
//Perform you task
}
Note : This is just pseudo code, might contain error or syntax problems
I am attempting to share an image with a hashtag using UIActivityViewController and I am encountering some strange behavior when attempting to share to Twitter, Facebook and Instagram. There does not seem to be a lot of documentation about these service's share extensions.
Scenario 1: Init controller with activity item array with image and text
If I initialize the controller like so, Twitter and Facebook will show up in the controller (no Instagram as it does not support text items), and both will programmatically pre-populate the hashtag in the text entry field:
let activityVC = UIActivityViewController(activityItems: [myHashtagString, myImage], applicationActivities: nil)
Scenario 2: Init controller with only image
In this scenario, all networks show up, but I (obviously) lose the automatic hashtag feature:
let activityVC = UIActivityViewController(activityItems: [myImage], applicationActivities: nil)
Scenario 3: UIActivityItemSource subclass
If I make my own UIActivityItemSource subclass, I can almost get everything to work. However, and this is what I cannot figure out, using the protocol methods as I have below results in the automatic hashtag working for Facebook, but not Twitter. How can this be possible -- is there a special key needed for Twitter? There must be a way for it to work if it works in Scenario #1...
Interestingly, this method works for both Twitter and Facebook if I insert a URL (commented out). So why on earth won't the text work for Twitter!?
let activityItem = CustomItemSource(image: image, message: "#TestTag")
let activityVC = UIActivityViewController(activityItems: [activityItem], applicationActivities: nil)
...
class CustomItemSource: NSObject, UIActivityItemSource {
private var image: UIImage!
private var message: String!
// MARK: Init
init(image: UIImage, message: String) {
super.init()
self.image = image
self.message = message
}
// MARK: Item Source Protocol
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return image
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
if activityType == .postToTwitter || activityType == .postToFacebook {
//return ["url": URL(string: "https://www.google.com")!, "image": image]
return ["text": message, "image": image]
}
else {
return ["image": image]
}
}
}
Define two UIActivityItemSource classes, one for Image and one for Text.
In first one only return the image.
In second one return NSObject() for placeHolder, and return Text or nil depending on activity. By returning NSObject(), UIActivity will allow all services to be available.
UIActivityViewController(activityItems: [ImageProvider(), TextProvider()], applicationActivities: nil)
and providers:
class TextProvider: NSObject, UIActivityItemSource {
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return NSObject()
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
if activityType == .postToTwitter || activityType == .postToFacebook {
return "Tweet with #Hashtag"
}
return nil
}
}
class ImageProvider: NSObject, UIActivityItemSource {
func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any {
return UIImage(named: ...)
}
func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
return UIImage(named: ...)
}
}
Explaination
First of all, Keys are not really sensitive, The only sensitive-key was "subject" for email and apps supporting it, which is implemented in UIActivityController's API and we can set it directly. It doesn't matter if you provide UIImage with key "image" or "1".
As it turns out, Twitter activity will not work if it's text is not returned directly in ...itemForActivity... method. So the solution is to separate item sources.
Twitter activity also will not work, if placeholder receives anything other than String, but by returning String Instagram activity will not work, So by returning NSObject() Type will be ignored and all services will be available.
if you want to limit some services use UIActivityViewController.excludedActivityTypes
Im trying to send data (NSData) from my app on one iOS Device to another via AirDrop using the UIActivityViewController. I have created a new CSM (custom data type) in my apps plist. The public.filename-extension = ppm.
So how do I add the ppm extension to the NSDate object I'm trying to send ?? Am I right in thinking that when a you present a UIActivityViewController, my apps Icon will not be displayed in the UIActivityViewController window if the object Im sending does not have my apps public extension (ppm) ??.... yea, I'm really confused !!
Heres the code I'm using to present UIActivityViewController
#IBAction func shareButton(sender: AnyObject) {
// myData is the object I want to send to be used in my app on another device
let vc = UIActivityViewController(activityItems: [myData],applicationActivities: [])
presentViewController(vc, animated: true, completion: nil)
}
Basically, all I'm trying to do is send custom data to be used in my app
You should take a look at the AirDrop sample code that covers the case of defining your own file type and sharing that with your app on the other device. The key part if you want to share raw data is that you have to create an instance of UIActivityItemSource and pass that to UIActivityViewController. Something like this:
class DataActivityItemSource: NSObject, UIActivityItemSource {
let myData: NSData
let typeIdentifier: String
let subject: String
let previewImage: UIImage
init(myData: NSData, typeIdentifier: String, subject: String, previewImage: UIImage) {
self.myData = myData
self.typeIdentifier = typeIdentifier
self.subject = subject
self.previewImage = previewImage
}
// called to determine data type. only the class of the return type is consulted. it should match what -itemForActivityType: returns later
#objc func activityViewControllerPlaceholderItem(activityViewController: UIActivityViewController) -> AnyObject {
return myData
}
// called to fetch data after an activity is selected. you can return nil.
#objc func activityViewController(activityViewController: UIActivityViewController, itemForActivityType activityType: String) -> AnyObject? {
return myData
}
// if activity supports a Subject field. iOS 7.0
#objc func activityViewController(activityViewController: UIActivityViewController, subjectForActivityType activityType: String?) -> String {
return subject
}
// UTI for item if it is an NSData. iOS 7.0. will be called with nil activity and then selected activity
#objc func activityViewController(activityViewController: UIActivityViewController, dataTypeIdentifierForActivityType activityType: String?) -> String {
return typeIdentifier
}
// if activity supports preview image. iOS 7.0
#objc func activityViewController(activityViewController: UIActivityViewController, thumbnailImageForActivityType activityType: String?, suggestedSize size: CGSize) -> UIImage? {
// look at suggestedSize and resize image (see AirDrop sample code for how to do this)
return previewImage
}
}
#IBAction func shareButton(sender: AnyObject) {
// myData is the object I want to send to be used in my app on another device
let itemSource = DataActivityItemSource(myData, "com.foo.ppm.typeIdentifier", "My Amazing Journey", aPreviewImage)
let vc = UIActivityViewController(activityItems: [itemSource],applicationActivities: [])
presentViewController(vc, animated: true, completion: nil)
}