Alright I think I am close to a solution here. I think I must be missing something small. Hope you guy can help.'
I am trying to have another app open another custom app and run a method from that app that is being called through the URL scheme. I understand that in ios 9 they made it manitory to define in the info.plist the key
<key>LSApplicationQueriesSchemes</key>
<array>
<string>URLScheme0</string>
<string>URLScheme1</string>
<string>URLScheme2</string>
ect....
</array>
And I think I have done that properly. Though I want a confirm on this and other thing. Firstly, do I add this to the info.plist of the "calling" app, or the "receiving" app, or BOTH? As, I have it now it is with both. When I remove it from the calling apps plist I get the error.
"This app is not allowed to query for scheme xxx”
Keep in mind I have also included in the plist for the receiving app the URL types and URL schemes array with the same scheme names.
The the calling app I have a button mapped with this methods code:
- (IBAction)killMethod:(id)sender {
NSString *customURL = #"TurnOffRelay://";
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:customURL]]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
} else {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"URL error" message:#"No custom URL defined for Kill Relay" preferredStyle:UIAlertControllerStyleAlert];
[self presentViewController:alert animated:YES completion:nil];
}
}
and for the receiving app I have in the appDelegate.m :
- (BOOL)application:(UIApplication *)application OpenURL:(NSURL *)url sourceApplication:(NSString *) sourceApplication annotation:(id)annotation {
NSLog(#" Calling application: %#", sourceApplication);
NSLog(#"URL scheme: %#", [url scheme]);
if ([sourceApplication isEqualToString:#"net.ble.relay"]) {
if ([[url scheme] isEqualToString:#"TurnOffRelay://"]) {
ViewController *viewController = [[ViewController alloc] init];
[viewController killSwitch];
NSLog(#"Running killSwitch");
}
return YES;
}
else
return NO;
}
With what I have right now running I am able to actually press the button in the "calling" app and from there the "receiving" app opens, but alas, the method I want to run doesn't run inside of the if statements. I am wondering what I am doing wrong. I will gladly answer any questions about things I may have missed. This has been bothering me all day. Would like some sort of guidance. Thanks in advance.
pay attention to if ([[url scheme] isEqualToString:#"TurnOffRelay://"]) 。 url scheme is TurnOffRelay rather than TurnOffRelay://.
So, after changing the OpenURL to openURL and then noticing that the sourceApplication name was wrong. I am guessing that if I had typed in the correct application to use, as in, the actual name of the application that was "calling" the If block would have proceeded correctly. But I am sure, also, that if I had not changed the openURL I would have been stuck again.
Thanks for the help. Its now working as intended.
Related
This is a very strange problem because my Facebook login was working before I updated to Xcode 6 and iOS 8. To make this even more strange Twitter is working excellent but Facebook isn't calling the didLogin callback.
Here is what I am doing in my AppDelegate:
#interface AppDelegate : UIResponder <UIApplicationDelegate, NSURLConnectionDataDelegate, UITabBarControllerDelegate, PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
Then I setup Facebook & Twitter in application:didFinishLaunchingWithOptions:
[Parse setApplicationId:PARSE_APPLICATION_ID
clientKey:PARSE_CLIENT_KEY];
[PFFacebookUtils initializeFacebook];
[PFTwitterUtils initializeWithConsumerKey:TWITTER_CONSUMER_KEY
consumerSecret:TWITTER_CONSUMER_SECRET];
After setting these up I setup my rootViewController like so:
self.welcomeViewController = [[ConfigViewController alloc] init];
self.navController = [[UINavigationController alloc] initWithRootViewController:self.welcomeViewController];
[self.navController setNavigationBarHidden: NO];
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
In the viewDidAppear of my ConfigViewController I do the following check:
// Force logout for testing
//[(AppDelegate *)[[UIApplication sharedApplication] delegate] logOut];
// If not logged in, present login view controller
if (![PFUser currentUser]) {
[(AppDelegate *)[[UIApplication sharedApplication] delegate] presentLoginViewControllerAnimated:NO];
return;
}
// Present UI
[(AppDelegate *)[[UIApplication sharedApplication] delegate] presentTabBarController];
At this point if the user is not logged in the following happens in presentLoginViewControllerAnimated:
// Customize the Log In View Controller
loginViewController = [[LoginViewController alloc] init];
loginViewController.delegate = self;
loginViewController.facebookPermissions = #[#"email",#"public_profile",#"user_friends"];
loginViewController.fields = PFLogInFieldsUsernameAndPassword | PFLogInFieldsTwitter | PFLogInFieldsFacebook | PFLogInFieldsSignUpButton | PFLogInFieldsPasswordForgotten | PFLogInFieldsLogInButton;
// Customize the Sign Up View Controller
signUpViewController = [[SignupViewController alloc] init];
signUpViewController.delegate = self;
signUpViewController.fields = PFSignUpFieldsDefault;
loginViewController.signUpController = signUpViewController;
[self.welcomeViewController presentViewController:loginViewController animated:NO completion:nil];
Here the loginViewController is presented. If the user taps on the twitter button he will login without any trouble. If the Facebook button is tapped however, the Facebook confirm screen shows up, I hit ok, then it returns to my loginViewController. I need for this to be called:
- (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user
So that I can dismiss the loginViewController and also perform any additional actions. Any idea as to why this could be happening?
Again, Why loginViewController:didLogInUser: delegate not being called for Facebook?
Any help is GREATLY appreciated!
[EDIT]
After much testing and many headaches here is the latest on this.
If I screw up the URL Schemes in my Info.plist it works. I changed the name from URL Schemes to URL Scheme and I get the following error:
FBSDKLog: Cannot use the Facebook app or Safari to authorize, fb6************** is not registered as a URL Scheme
Even though I get this error, I am getting a screen popup to log into FaceBook. I fill it out and I am in, it works, I can login with Facebook. This doesn't seem convenient but it is working.
Other tests/things I tried were downloading the Facebook app and trying to login, login without the Facebook app (through safari), implementing the delegates in my welcomeViewController instead of my AppDelegate, and updating Parse/Facebook SDKs.
I think the problem might have something to do with opening up another app such as Facebook or safari. The reason I am leaning towards this is because the twitter screen is a modally popped up view and it works without an issue. When Facebook gives me this error, it doesn't switch to safari or the Facebook app, instead it shows a modally popped up login and it works fine. This leads me to believe that the problem is related to switching apps and not receiving the callback properly.
I also have a third login option which I neglected to mention. This third option works just by signing up without a social media account, and this is also working.
HUGE thanks to Matt Tang for pointing me in the right direction.
It turns out that I had accidentally deleted/commented out portions of these 3 callbacks, this was the source of the problem. In the end, the solution for me was to implement application:handleOpenURL: and application:openURL:sourceApplication:annotation:
// Facebook oauth callback
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
return [FBSession.activeSession handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [FBAppCall handleOpenURL:url sourceApplication:sourceApplication withSession:[PFFacebookUtils session]];
}
and to uncomment this line:
[FBAppCall handleDidBecomeActiveWithSession:[PFFacebookUtils session]];
Which I had inside of this call back:
- (void)applicationDidBecomeActive:(UIApplication *)application;
For me, the reason was switching to a testing FB app, where you need to change the appID. The requests then have different tokens, particularly the former token I used ( not the one generated after creating a test app on FB).
The solution for me was to delete the app from simulator and run it again.
I have registered my app to be able to open HTML files. I would like the app to keep the last HTML file it opened... If I open a new HTML file, I would like it to overwrite the last one opened.
I have attempted to user the Documents directory and its not working for me. I have also tried using NSUserDefaultsto no avail. Here is what i currently have:
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
ViewController *vc = (ViewController *)self.window.rootViewController;
[vc loadFileWithUrl:url];
[[NSUserDefaults standardUserDefaults] setURL:[url fileReferenceURL] forKey:#"amd"];
return YES;
}
I kill the application entirely, then - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions is called. Here is how that method looks:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *url = [[NSUserDefaults standardUserDefaults] URLForKey:#"amd"];
if (url)
{
ViewController *vc = (ViewController *)self.window.rootViewController;
[vc loadFileWithUrl:url];
}
return YES;
}
url is always nil :(
PS: I have also tried storing the HTML file in its string representation, and I am able to get that to persist in the Documents folder, but when I try to load that string using:
[webView loadHTMLString:htmlString]; the page never loads. I think that has something to do with the Javascript but I'm not too sure.
The user defaults are saved when the app goes to the background, or when you call -synchronize on the user defaults. When developing, you often don't put the app into background, but just kill it through XCode, in which case nothing gets saved. You can save the user defaults by pressing the home button on your iPhone/iPad, and killing the app in XCode 1second later.
Also, you should put a log statement into your first method, like NSLog(#"saving amd to %#", [url fileReferenceURL]); to be sure that it really gets saved!
It seems that you forgot to call
[[NSUserDefaults standardUserDefaults] synchronize];
Docs:
Writes any modifications to the persistent domains to disk and updates
all unmodified persistent domains to what is on disk.
I tried to open facebook app using this
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"fb://"]];
when my app is running in foreground , it works fine but if my app is in background it didn't work .
help me out .
I'm very new in programming
You are think impossible task. Think and first ask your self what are you trying.
Your app in to background it means (minimized). then where to trigger for calling open Facebook Native app method.
If app in background then you can't have any event for handle your app event from iPhone screen.
That bellow code for open Fb native app from app. but from background it out of logic think. that not relevant at all.
you can open facebook app using this bellow :-
- (IBAction)OpenFB: (id) sender
{
NSURL* facebookURL = [NSURL URLWithString: #"fb://profile/157893597658332"];
UIApplication* app = [ UIApplication sharedApplication ];
if( [ app canOpenURL: facebookAppURL ] ) {
[ app openURL: facebookAppURL ];
} else {
// url wrong
}
}
Here it is very nice Article
http://www.plungeinteractive.com/blog/2012/12/31/open-facebook-and-twitter-native-apps-from-your-ios-appgame/
UPDATE:-
I dont think this is suitable for your requirement but using Custom URL Scheme. you can able to Open your app from from safari browser or other app. just setting URL type--> setting URL schemes like bellow
and then try like i did in bellow image that open your app from browser:-
You cannot launch another app from the background mode because that would be pre-empting the user's current task without user interaction. There is only one application that is permitted to pre-empt the user's current action and that is the phone in the case of an incoming call.
What you could do is display a local notification and if the user actions that notification to launch your app - placing it back into foreground - then you could launch Facebook.
UILocalNotification* localNotification = [[UILocalNotificationalloc] init];
localNotification.fireDate = nil;
localNotification.alertBody = #"I want to launch Facebook";
localNotification.timeZone = nil;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
then in your app delegate -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Handle launching from a notification
UILocalNotification *locationNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (locationNotification) {
// Open Facebook
[application openURL:[NSURL URLWithString:#"fb://"];
}
return YES;
}
But if the user chooses not to action your notification there is nothing you can do.
I am on some document sharing issue. My iPhone has two applications. One app "SharingApp" shares a file from its bundle to another app "ViewerApp" using Document Interaction Controller. By default, the shared file will be saved to the document directory of "ViewerApp" under folder named "Inbox". I can get the url in didFinishLaunchingWithOptions: of "ViewerApp" as
NSURL *url = (NSURL*)[launchOptions valueForKey: UIApplicationLaunchOptionsURLKey];
This scenario works perfectly if the "ViewerApp" is not been launched.
The problem I have is, incase, if the "ViewerApp" is in background state(or not killed) and if the file is shared from "SharingApp", applicationDidBecomeActive: is called in appDelegate of "ViewerApp". So, I couldn't able to get the url as the didFinishLaunchingWithOptions: method is not called(ViewerApp is already launched). "ViewerApp" just opens with the last shared url before entering to the background state.
How can I handle to get the url in applicationDidBecomeActive:? Please, share some ideas if you have come across this kind of issue.
Thanks for your ideas.
You should implement the following UIApplicationDelegate method
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
This should solve your problem since this method will be called when your viewer app is in background
I ran into this exact same issue. The problem is that didFinishLaunchingWithOptions is not called when an application is already open but brought to the foreground. I took my code out of didFinishLaunchingWithOptions and instead put it inside handleOpenURL (also on the app delegate page)
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url{
if (url != nil && [url isFileURL])
{
MainViewController *frontViewController = [[MainViewController alloc] init];
[frontViewController handleOpenURL:url]; //function on my main view controller class to do the necessary action
return YES;
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Cannot Handle Opening This File." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert performSelectorOnMainThread:#selector(show) withObject:nil waitUntilDone:YES];
return NO;
}
}
Since iOS6, I can't tell whether the application can launch Safari or not.
If Safari is restricted on the device (Settings>General>Restrictions), nothing happens when trying to open a URL, and there's no indication of what went wrong:
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];
[[UIApplication sharedApplication] canOpenURL:url]; // Returns YES
[[UIApplication sharedApplication] openURL:url]; // Returns YES
However, Safari does not launch, and the user is left wondering why my buttons are "broken".
This seems like a bug to me so I filed a radar #12449905.
Is there another way to solve this problem?
If this is an Apple bug, then it looks like the thing for you to do is to program around it. Once the user clicks the button, you can always write something like this:
[self performSelector:#selector(notifyUserOfRestrictedAccess) withObject:self afterDelay:.5];
In the app delegate, you can set a property such as:
- (void)applicationWillResignActive:(UIApplication *)application {
self.openingExternalProgram = YES;
}
In your view controller, create the method like this:
-(void) notifyUserOfRestrictedAccess {
if (!appDelegate.openingExternalProgram) {
// Message the user via UIAlertView about restricted Safari access
}
appDelegate.openingExternalProgram = NO;
}
I'm sure there are better ways, but at least you don't have to wait on Apple.