Add shareToSms function to Cordova ShareKit Plugin - objective-c

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);

Related

Using a method in Objective-C cocoa

I'm having trouble with something very basic. I want to call this action:
- (IBAction)changeGreeting:(id)sender {
self.userName = self.textField.text;
NSString *nameString = self.userName;
if ([nameString length]==0) {
nameString = #"World";
}
NSString *greeting = [[NSString alloc] initWithFormat:#"Hello, %#!", nameString];
self.label.text = greeting;
}
When the user presses return after entering text in the text field. This is what I have:
-(BOOL)textFieldShouldReturn:(UITextField *)theTextField{
if (theTextField == self.textField) {
[theTextField resignFirstResponder];
[changeGreeting];
}
return YES;
}
I'm not sure what to put where it says "changeGreeting." Think I'm missing the concept here. Thanks for any help.
Your syntax is wrong. Try this:
[self changeGreeting:self];
In Objective-C the syntax for sending messages (calling functions) is like this:
[receiver message];
Since you implement the changeGreeting: method in the same class as you're calling it from, the receiver will be self. As the parameter (sender) you usually pass the object that sends the message, but since you don't use it in your implementation of changeGreeting: it doesn't really matter what you pass there.
you called the changeGreeting function in wrong way
you should call it like
[self changeGreeting:nil];
Or if you want to track something from the textField then
[self changeGreeting:theTextField];
the sender will get theTextField as parameter if you need some processing on based on the textField.

UIActivityItemSource Protocole set complex object

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

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")

CLGeocoder reverseGeocodeLocation. First time in [placemarks count = 0]?

I am new to ObjC and I am struggling with the CLGeocoder. I want to be able to use reverseGeocodeLocation to obtain a string that contains the user location that I pass to my delegate when the user presses a Done button.
So the user triggers the display of a MapViewController, I call the reverseGeocodeLocation in the viewDidLoad but the [placemarks count = 0] this first time in, and I have no placemark to get the info that I need. The second time the user triggers the display of the MapViewController the placemarks array has been populated and everything works.
I suspect it is something to do with the reverseGeocodeLocation being an asynchronous call - but I cannot figure out how to solve this problem. I have tried searching online but nothing seems to help me understand what I am doing wrong and how i can solve this issue. Thanks in advance.
#interface MapViewController ()
#property (strong, nonatomic) CLGeocoder *geocoder;
#property (readwrite, nonatomic) NSString *theLocationName;
#end
#implementation MapViewController
#synthesize mapView, geocoder, delegate = _delegate, theLocationName = _theLocationName;
- (void)viewDidLoad
{
[super viewDidLoad];
self.mapView.delegate=self;
self.mapView.showsUserLocation = YES;
[self theUserLocation];
}
-(void)theUserLocation
{
if (!geocoder)
{
geocoder = [[CLGeocoder alloc] init];
}
MKUserLocation *theLocation;
theLocation = [self.mapView userLocation];
[geocoder reverseGeocodeLocation:theLocation.location
completionHandler:^(NSArray* placemarks, NSError* error)
{
if ([placemarks count] > 0)
{
CLPlacemark *placemark = [placemarks objectAtIndex:0];
[self setTheLocationName: placemark.locality];
}
}];
- (IBAction)done:(id)sender
{
[[self delegate] mapViewControllerDidFinish:self locationName:[self theLocationName]];
}
#end
This is not exact answer to your question but, if you can switch to other solution apart from CLGeocoder than following function can help you to get address from given latitude, longitude
#define kGeoCodingString #"http://maps.google.com/maps/geo?q=%f,%f&output=csv" //define this at top
-(NSString *)getAddressFromLatLon:(double)pdblLatitude withLongitude:(double)pdblLongitude
{
NSString *urlString = [NSString stringWithFormat:kGeoCodingString,pdblLatitude, pdblLongitude];
NSError* error;
NSString *locationString = [NSString stringWithContentsOfURL:[NSURL URLWithString:urlString] encoding:NSASCIIStringEncoding error:&error];
locationString = [locationString stringByReplacingOccurrencesOfString:#"\"" withString:#""];
return [locationString substringFromIndex:6];
}
Credit : Selected Answer to this question
So the user triggers the display of a MapViewController, I call the reverseGeocodeLocation in the viewDidLoad but the [placemarks count = 0] this first time in, and I have no placemark to get the info that I need. The second time the user triggers the display of the MapViewController the placemarks array has been populated and everything works.
It's not because the call is asynchronous - it's because the first time you call theUserLocation the actual location isn't available. Getting the user's location is not instantaneous - it takes time. However, you're asking for the user's location as soon as the map loads, which in most circumstances won't work.
What you need to do is hook into the MKMapViewDelegate methods, which provide you with callbacks when the location is updated. You can use this to check the location's accuracy, and decide whether it is accurate enough for you to reverse geolocate.

Need to retain a CFSocketRef?

I am facing a problem: I have two view controllers, viewController1, and viewController2.
Here is the method I'm concerned about in viewController1:
-(void)msgToServer:(NSString*)identifier:(NSString *)_username{
NSString *message = [NSString stringWithFormat:#"%#|%#|<END>", identifier, _username];
CFDataRef messageData = (CFDataRef)[message dataUsingEncoding:NSUTF8StringEncoding];
CFSocketSendData(s, NULL, messageData, 0);
}
this method is working perfectly in viewController1.
Now I am calling this method from viewController2. I am passing two arguments, identifier and _username. It generates the string perfectly, but when it reaches the last line it misses the value of s -- which is a CFSocketRef.
What should I do so that s will retain its value, even if I am in viewController2?
Code from viewController2 which calls the above method:
- (void)viewDidLoad {
[super viewDidLoad];
WatchListViewController *watchListViewController = [[WatchListViewController alloc]init];
[watchListViewController msgToServer:#"PREQ" :userName];
}
Thanks in advance.
you could use the retain function of NSObject.
- (id)retain
See in Apple Documentation
Also have a look to Object Ownership and Disposal in Memory Management Programming Guide
EDITED:
Try with below code
You might have issue with function prototype,not with retaining.
use below
-(void)msgToServer:(NSString*)identifier withUsername:(NSString *)_username;.
- (void)viewDidLoad {
[super viewDidLoad];
WatchListViewController *watchListViewController = [[WatchListViewController alloc]init];
[watchListViewController msgToServer:#"PREQ" withUsername:userName];
}
-(void)msgToServer:(NSString*)identifier withUsername:(NSString *)_username{
NSString *message = [NSString stringWithFormat:#"%#|%#|<END>", identifier, _username];
CFDataRef messageData = (CFDataRef)[message dataUsingEncoding:NSUTF8StringEncoding];
CFSocketSendData(s, NULL, messageData, 0);
}
Thanx to all who helped me well i solved this problem in this way:
when I push from viewController1 to viewController2 i am passing two parameters "username" and "s" to viewController2 and then I write this method in viewController2.
-(void)msgToServer:(NSString*)identifier:(NSString *)_username{
NSString *message = [NSString stringWithFormat:#"%#|%#|<END>", identifier, _username];
CFDataRef messageData = (CFDataRef)[message dataUsingEncoding:NSUTF8StringEncoding];
CFSocketSendData(s, NULL, messageData, 0);
}
then I am calling this method in the same view controller and it works perfectly. I think this is the only solution which i find. if any body can make it more efficient then you are welcome. :)