UIActivityItemSource Protocole set complex object - objective-c

I'm using iOS 6 new way to share information : UIActivityViewController. To select the shared data depending on the media (facebook, twitter or mail) my view controller implement the UIActivityItemSource Protocol as follow :
- (IBAction)onShareButton:(UIButton *)sender
{
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:#[self] applicationActivities:nil];
activityViewController.excludedActivityTypes = #[UIActivityTypeMessage, UIActivityTypeAssignToContact, UIActivityTypeCopyToPasteboard, UIActivityTypeMessage, UIActivityTypePostToWeibo, UIActivityTypePrint, UIActivityTypeSaveToCameraRoll];
[self presentViewController:activityViewController animated:YES completion:^{}];
}
#pragma mark - UIActivityItemSource Protocol
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType {
if ([activityType isEqualToString:UIActivityTypePostToFacebook]) {
NSArray *items = #[#"message facebook", [NSURL URLWithString:#"http://www.myUrlFacebook.com"]];
return items;
} else if ([activityType isEqualToString:UIActivityTypePostToTwitter]) {
NSArray *items = #[#"message twitter", [NSURL URLWithString:#"http://www.myUrlTwitter.com"]];
return items;
} else if ([activityType isEqualToString:UIActivityTypeMail]) {
NSArray *items = #[#"message mail", [NSURL URLWithString:#"http://www.myUrlMail.com"]];
return items;
}
NSArray *items = #[#"Not a proper Activity", [NSURL URLWithString:#"http://www.myUrlMail.com"]];
return items;
}
- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController {
return #"PlaceHolder";
}
When I'm returning a simple NSString for activityViewController:itemForActivityType: the string is well used by my UIActivityViewController, but I can't find a way to use an Array !
According to Apple Documentation it should be possible :
This method returns the actual data object to be acted on by an activity object
Apple documentation
Does anyone ever use this UIActivityItemSource Protocol with Arrays, or is there a use full tutorial to do that ?
Note : I also got this error on the console, it may help ...
Launch Services: Registering unknown app identifier com.apple.mobilemail failed
Launch Services: Unable to find app identifier com.apple.mobilemail

A single object conforming to UIactivityItemSource can only return a single piece of data for activityViewControllerPlaceholderItem:, no NSArrays.
You could overcome this by creating and passing two UIActivityItemSources in the activityItems part of the initial initWithActivityItems:. Each source can pass a placeholder value, but can return something blank on itemForActivityType so you don't actually have to use that particular type of data depending on the activity.
Or just use that cool extension mentioned in the other answer.

After spending a significant amount of time trying to figure this one out, it seems it isn't possible to pass it an NSArray of items. So I extended UIActivityViewController to make it possible.
RDActivityViewController

Related

UIImage only for the chosen applicationActivities, but NSString for all applicationActivities

I'm using UIActivityViewController for share NSString and UIImage, but I don't want to share the UIImage with iMessage & e-mail.
How can I create such a custom UIActivity for UIImage and leave NSString for all?
When you create your UIActivityViewController, you pass along an array of activity items.
And the objects you pass along in that array can be objects that adopt the UIActivityItemSource protocol.
And if you send along a UIImage, why not create a "ImageItemProvider" object and then implement your own "activityViewController:itemForActivityType:" method that returns "nil" if you don't want to share the image via iMessage or email.
E.G.:
//- Returns the data object to be acted upon. (required)
- (id)activityViewController:(UIActivityViewController *)activityViewController itemForActivityType:(NSString *)activityType
{
if ([activityType isEqualToString:UIActivityTypeMail]) {
return nil;
}
if ([activityType isEqualToString:UIActivityTypeMessage]) {
return nil;
}
return [UIImage imageNamed:#"the image you wanted returned"];
}
I'm basing this answer on the code I found in this tutorial.

Add shareToSms function to Cordova ShareKit Plugin

I would like to implement a function to directly share to Sms in the ShareKit Plugin. It have 3 builted-in function to share directly to Facebook, Mail and Twitter. I took a look in plugin code and it seems to me pretty easy, taking as example the function
shareToMail(subject,body);
- (void)shareToMail:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
[SHK setRootViewController:self.viewController];
SHKItem *item;
NSString *subject = [arguments objectAtIndex:1];
NSString *body = [arguments objectAtIndex:2];
item = [SHKItem text:body];
item.title = subject;
[SHKMail shareItem:item];
}
It seems that it takes as input the two parameters passed in (objectAtIndex:1 and objectAtIndex:2) and then it assign them to the item object (item = [SHKItem text:body];) for send it to SHKMail method.
That is what I understood, but I'm really a noob in ObjC, so... can someone give me some advice in how to create a function that call the Sms method? I think it is called SHKTextMessage but once again I'm really not sure about this...
if someone need this...
In ShareKitPlugin.m add this:
//at the top, near the other import
#import "SHKTextMessage.h"
//somewhere between #implementation ShareKitPlugin and #end
- (void)shareToSms:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
[SHK setRootViewController:self.viewController];
SHKItem *item;
NSString *message = [arguments objectAtIndex:1];
item = [SHKItem text:message];
[SHKTextMessage shareItem:item];
}
In the ShareKitPlugin.js add:
ShareKitPlugin.prototype.shareToSMS = function( message)
{
cordova.exec(null, null, "ShareKitPlugin", "shareToSms", [message] );
};
And now you can share trought Sms using this function:
window.plugins.shareKit.shareToSMS(message);

Different data for sharing providers in UIActivityViewController

I'm trying to use an UIActivityViewController with one long NSString as the data. If I put a string > 140 characters, the tweet sheet in it does not display the string. And if I truncate the string before giving it to the controller, all of the UIActivities have the truncated string. I don't want Facebook or Message to be truncated.
Is there a way to give different strings to different UIActivities?
Thank you!
(e.g. Marco Arment's The Magazine app does this by having a truncated string followed by #TheMagazineApp in UIActivityPostToTwitter, and other stuff in other UIActivities.)
I think this is what you're looking for: Custom UIActivityViewController icons and text.
You should be able to provide different data for each activity type.
Hope this helps somebody. It's pretty straightforward if you subclass UIActivityItemProvider:
#interface MyActivityItemProvider : UIActivityItemProvider
#end
#implementation MyActivityItemProvider
- (id)item
{
// Return nil, if you don't want this provider to apply
// to a particular activity type (say, if you provide
// print data as a separate item for UIActivityViewController).
if ([self.activityType isEqualToString:UIActivityTypePrint])
return nil;
// The data you passed while initialising your provider
// is in placeholderItem now.
if ([self.activityType isEqualToString:UIActivityTypeMail] ||
[self.activityType isEqualToString:UIActivityTypeCopyToPasteboard])
{
return self.placeholderItem;
}
// Return something else for other activities. Obviously,
// you can as well reuse the data in placeholderItem here.
return #"Something else";
}
#end
Then pass its instance with an array of activity items to UIActivityViewController:
MyActivityItemProvider *activityItem =
[[MyActivityItemProvider alloc] initWithPlaceholderItem:#"Your data"];
NSArray *sharingItems = [NSArray arrayWithObjects:
activityItem, _myUITextView.viewPrintFormatter, nil];
UIActivityViewController *activityController =
[[UIActivityViewController alloc]
initWithActivityItems:sharingItems applicationActivities:nil];
This can be easily done by using the optional activityType property from the UIActivityItemProvider object. That property returns a UIActivityType, so you can do something like:
class PhotoActivityItemProvider: UIActivityItemProvider {
...
override var item: Any {
guard let activityType = self.activityType else {
return photoURL.absoluteString
}
if activityType == .mail || activityType == .message {
return "The photo link is \(photoURL.absoluteString)."
}
...
}
More information in my blog post: https://www.whitesmith.co/blog/control-what-youre-sharing/
You can create a class that conforms to UIActivityItemSource and then pass its instance with an array of activity items to UIActivityViewController:, as #Mu-Sonic suggested.
If you want to know in which platform is the user sharing and return any specific data dependent on the tapped platform, override public func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any?

How to get localized Cancel, Done and etc?

UIBarButtonItem have identifiers like Cancel, Done and some others. They are shown as text to user. If user changes language then for example Cancel button will be translated automatically. And as developer you do not need to provide localization string for this buttons. It means that Cancel, Done and other strings already localized and comes together with OS.
Is here a way to get this strings programmatically?
I do not want to add additional strings to localization files. And if it is possible to access then it would be very good.
Here's a little macro I created to get the System UIKit Strings:
#define UIKitLocalizedString(key) [[NSBundle bundleWithIdentifier:#"com.apple.UIKit"] localizedStringForKey:key value:#"" table:nil]
Use it like this:
UIKitLocalizedString(#"Search");
UIKitLocalizedString(#"Done");
UIKitLocalizedString(#"Cancel");
...
One (admittedly questionable) way of accomplishing this easily is use Apple's framework bundle localizations directly:
To see what they have to offer, open the following directory via the Finder:
/Applications/Xcode/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator6.1.sdk/System/Library/Frameworks
And in your case, you'll subsequently open ./UIKit.framework/English.lproj/Localizable.strings (in TextMate). Here you see a wide variety of translations that Apple uses for things like "Print", "OK", "On", "Off", etc. The real magic is that there are about 35 different language translations that you can copy into your own Localizable.strings files, for free.
If you are incredibly brazen and don't mind putting your app's future stability in question, you could skip the whole "copy into your own Localizable.strings" process and go straight to the source programmatically:
NSBundle *uiKitBundle = [NSBundle bundleWithIdentifier:#"com.apple.UIKit"];
NSString *onText = uiKitBundle ? [uiKitBundle localizedStringForKey:#"Yes" value:nil table:nil] : #"YES";
NSString *offText = uiKitBundle ? [uiKitBundle localizedStringForKey:#"No" value:nil table:nil] : #"NO";
Caveat: In no way do I recommend that you actually access these localized resources programmatically in an app that you intend to submit to the App Store. I'm merely illustrating a particular implementation that I've seen which addresses your original question.
Encouraged by Answer to this Question (by Stephan Heilner)
and Answer (by bdunagan) for iPhone/iOS: How can I get a list of localized strings in all the languages my app is localized in?
Objective-C
NSString * LocalizedString(NSString *key) {
return [[NSBundle mainBundle] localizedStringForKey:key];
}
#interface NSBundle(Localization)
- (NSString *)localizedStringForKey:(NSString *)key;
- (NSDictionary<NSString *, NSString *> *)localizationTable;
#end
#implementation NSBundle(Localization)
- (NSDictionary<NSString *, NSString *> *)localizationTable {
NSString *path = [self pathForResource:#"Localizable" ofType:#"strings"];
NSData *data = [NSData dataWithContentsOfFile:path];
NSError *error = nil;
id obj = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:&error];
if (error && obj == nil) {
#throw error;
return nil;
}
if ([obj isKindOfClass:NSDictionary.class]) {
return obj;
}
#throw NSInternalInconsistencyException;
return nil;
}
- (NSString *)localizedStringForKey:(NSString *)key {
return [self localizedStringForKey:key value:nil table:nil];
}
#end
Swift 5
public extension String {
func localized(_ bundle: Bundle = .main) -> String {
bundle.localize(self)
}
var localized: String {
return localized()
}
}
extension Bundle {
static var UIKit: Bundle {
Self(for: UIApplication.self)
}
func localize(_ key: String, table: String? = nil) -> String {
self.localizedString(forKey: key, value: nil, table: nil)
}
var localizableStrings: [String: String]? {
guard let fileURL = url(forResource: "Localizable", withExtension: "strings") else {
return nil
}
do {
let data = try Data(contentsOf: fileURL)
let plist = try PropertyListSerialization.propertyList(from: data, format: .none)
return plist as? [String: String]
} catch {
print(error)
}
return nil
}
}
Usage:
"Photo Library".localized(.UIKit)
To get all keys of localized strings of UIKit:
Bundle.UIKit.localizableStrings?.keys//.map { $0 }
While perhaps not exactly what you were seeking, there is a commercial app in the Mac App Store called "System Strings" claiming that it provides a collection of more than 53000 standard localized strings. It was released November 2, 2012. I am in no way affiliated with this app or the author. The URL is https://itunes.apple.com/us/app/systemstrings/id570467776.
Sounds like what you are asking is if Apple provides a way to access a dictionary of pre-translated strings. I would think that anything provided by Apple for something like this would be located in their Docs: Internationalization Programming Topics
To answer your question I do not believe they provide a dictionary/list of known translations. Either you will have to define them in your Localizable.strings resource file or do as others have stated in the comments and pull the title from the UIBarButtonItem (I would go with the resource file personally).
Why not use base localization with your storyboard? It will localize it for you.
You could use
NSLocalizedString(#"Cancel", #"Cancel")

webview in iphone

I m passing an url as string from UIviewController to another uiviewcontroller..i was able to pass the url successfully but not able to load the string in the webview...in console i m getting a null value in webview could u guys help me out below is the code...
-(void)playAction1
{
webviewcontroller *newEnterNameController = [[webviewcontroller alloc] initWithItem:#"http://www.theappcodeblog.com/?p=222"];
[self.navigationController pushViewController:newEnterNameController animated:YES];
[newEnterNameController release];
}
- (id)initWithItem:(NSString *)url
{
if (self = [super initWithNibName:#"webviewcontroller" bundle:nil])
{
self.title=#"facebook";
self.url1 = [NSURL URLWithString:url];
//URL Requst Object
self.requestObj1 = [NSURLRequest requestWithURL:url1];
NSURLConnection *connection=[[[NSURLConnection alloc] initWithRequest:self.requestObj1 delegate:self]autorelease];
[self.webViewAnnouncements loadRequest:self.requestObj1];
NSLog(#"webView:%#",webViewAnnouncements);
[self.webViewAnnouncements setDelegate:self];
}
return self;
}
While what you're doing doesn't look wrong to me (in truth I'd need to see .h and .xib files) as well to be sure. I would consider the initWithItem to be an unusual pattern.
If I was you, I would init the view controller in the "normal" way using initWithNib and then create the URL as a property type and set it before you present the view controller to the screen.