I have intercepted URL opening by doing the following:
- (BOOL)openURL:(NSURL *)url{
URLViewController * web = [[URLViewController alloc] init];
web.url = url;
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:web];
[nav.navigationBar setTintColor:[UIColor blackColor]];
[nav setModalPresentationStyle:UIModalPresentationFormSheet];
[self.detailViewController presentModalViewController:nav animated:NO];
[web release];
[nav release];
return YES;
}
I have a UITextView in which detects URL and when clicking on the URL it opens up the link in a ModalViewController. Full detail on what's going on can be seen here. Now the issue is, what if I want to open a URL in safari, is it still possible?
You should add an override flag indicating whether you want to exercise control or not.
#interface MyApplication : UIApplication {
}
-(BOOL)openURL:(NSURL *)url withOverride:(BOOL)override;
#end
#implementation MyApplication
-(BOOL)openURL:(NSURL *)url withOverride:(BOOL)override {
if ( !override ) {
return [super openURL:url];
}
if ([self.delegate openURL:url]) {
return YES;
} else {
return [super openURL:url];
}
}
-(BOOL)openURL:(NSURL *)url{
return [self openURL:url withOverride:YES];
}
#end
So now all calls that you want to bypass can be sent like this.
[[MyApplication sharedApplication] openURL:url withOverride:NO];
Original Answer
This is what you should do. Put it before the return YES; statement.
if ( [super canOpenURL:aURL] ) {
return [super openURL:aURL];
}
Related
i have a problem in getting the GADInterstitial custom ads i have tried this code
if(nil != m_pBannerView)
{
m_pBannerView.delegate = nil;
[m_pBannerView release];
m_pBannerView = nil;
}
m_pBannerView = [[GADBannerView alloc] initWithAdSize:kGADAdSizeBanner];
m_pBannerView.delegate = self;
m_pBannerView.rootViewController = self;
m_pBannerView.adUnitID = #"AdMob Publisher ID";
m_pBannerView.rootViewController = self;
[self.view addSubview:m_pBannerView];
GADRequest *request = [GADRequest request];
request.testing = YES;
[m_pBannerView loadRequest:request];
if(nil != m_pInterstitial)
{
[m_pInterstitial release];
m_pInterstitial = nil;
}
m_pInterstitial = [[GADInterstitial alloc] init];
m_pInterstitial.delegate = self;
m_pInterstitial.adUnitID = #"INTERSTITIAL_AD_UNIT_ID";
GADRequest *interstialRequest = [GADRequest request];
interstialRequest.testing = YES;
[m_pInterstitial loadRequest: interstialRequest];
}
And in GADInterstitial Delegates i am calling [ad presentFromRootViewController:self];
but still i am not able to get the custom ads please help me.
You have to use your own unique id for adUnitID property
GADInterstitial is an interesting way to show ads in your Apps, and kind of a tricky one too. Following this example, lets pursue the following steps:
First we need to set up the environment for them to show at all.
Download the GoogleAdMobAdsSdkiOS, preferably the latest. Add
the SDK to your project, but do remember to delete the example
Projects in the AddOns folder in the SDK.
Next, add the following frameworks in your Project>>Build
Phases>>Link Binary With Libraries:
AdSupport.framework (select Optional if catering for < iOS7)
StoreKit.framework
CoreData.framework
CoreAudio.framework
AVFoundation.framework
MessageUI.framework
AudioTool.framework
libGoogleAdMobAds.a (placed in the SDK folder)
The basics are complete. Now we need to select the ViewController we wish to see our Ads in. So here's some code, here we import the header for GADInterstitialDelegate and extend it with our MainViewController.h:
#import "GADInterstitialDelegate.h"
#define kSampleAdUnitID #"/6253334/dfp_example_ad/interstitial"
#class GADInterstitial;
#class GADRequest;
#interface MainViewController : UIViewController<GADInterstitialDelegate>
{
BOOL isLoaded_;
NSTimer *quickie_;
}
#property(nonatomic, strong) GADInterstitial *interstitial;
//Make sure the delegate is handled properly.
Now we need to move to the implementation i.e. in MainViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// FOLLOW THE CODE BELOW FOR ADMOD INTERESTIAL IMPLEMENTATION
[self initializeAds];
quickie_ = [[NSTimer alloc] init];
quickie_ = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showAdd) userInfo:nil repeats:YES];
}
-(void)showAdd
{
if(isLoaded_ && [quickie_ isValid])
{
[quickie_ invalidate];
quickie_ = nil;
[self.interstitial presentFromRootViewController:self];
}
}
- (GADRequest *)request
{
GADRequest *request = [GADRequest request];
return request;
}
-(void)initializeAds
{
// Create a new GADInterstitial each time. A GADInterstitial will only show one request in its
// lifetime. The property will release the old one and set the new one.
self.interstitial = [[GADInterstitial alloc] init];
self.interstitial.delegate = self;
// Note: kSampleAdUnitId is a staticApId for example purposes. For personal Ads update kSampleAdUnitId with your interstitial ad unit id.
self.interstitial.adUnitID = kSampleAdUnitID;
[self.interstitial loadRequest:[self request]];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.loadingSpinner.center = CGPointMake(CGRectGetWidth(self.view.bounds) / 2, self.loadingSpinner.center.y);
}
- (void)interstitialDidReceiveAd:(GADInterstitial *)interstitial
{
isLoaded_ = YES;
}
- (void)interstitial:(GADInterstitial *)interstitial didFailToReceiveAdWithError:(GADRequestError *)error
{
isLoaded_ = NO;
}
//----ADS IMPLEMENTATION TILL HERE--->//
The timer "quickie_" here constantly checks if the Ad has successfully loaded and when it does, it shoots the Ad on the ViewController if the user still is on it. The static kSampleAdUnitID is a sampleId that always works. Thats it. Run your code and find your Interstitial Ad on your ViewController of choice.
Hope I helped. Cheers! :)
I have a custom UIButton class in my IPhone navigation application. When the user clicks the button I present a modal view which displays a tableview list of records that the user can select from.
On click of the button I create my viewController and show it using the following code:
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
dropDownPickerViewController = [[DropDownListingViewController alloc] initWithNibName:#"DropDownListingView" bundle:[NSBundle mainBundle]];
.....
.....
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] presentModalViewController:dropDownPickerViewController animated:NO];
[dropDownPickerViewController release];
[super touchesEnded:touches withEvent:event];
}
As you can see the button could be on any viewController so I grab the navigationController from the app delegate. Than in my DropDownPickerViewController code i have the following when a user selects a record:
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] dismissModalViewControllerAnimated:NO];
But nothing occurs. It seems to freeze and hang and not allow any interaction with the form. Any ideas on why my ModalViewController wouldnt be dismissing? Im thinking it is the way I use the app delegate to present the viewController. Is there a way to go self.ParentViewController in a UIButton class so I can get the ViewController of the view that the button is in (if this is the problem)?
Any ideas would be greatly appreciated.
Thanks
I did recall that I did have to do something similar once, and by looking at this post:
Get to UIViewController from UIView?
I was able to create some categories:
//
// UIKitCategories.h
//
#import <Foundation/Foundation.h>
#interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
#end
#interface UIView (FindUINavigationController)
- (UINavigationController *) firstAvailableUINavigationController;
- (id) traverseResponderChainForUINavigationController;
#end
//
// UIKitCategories.m
//
#import "UIKitCategories.h"
#implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
#end
#implementation UIView (FindUINavigationController)
- (UINavigationController *) firstAvailableUINavigationController {
// convenience function for casting and to "mask" the recursive function
return (UINavigationController *)[self traverseResponderChainForUINavigationController];
}
- (id) traverseResponderChainForUINavigationController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UINavigationController class]]) {
return nextResponder;
} else {
if ([nextResponder isKindOfClass:[UIViewController class]]) {
//NSLog(#" this is a UIViewController ");
return [nextResponder traverseResponderChainForUINavigationController];
} else {
if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUINavigationController];
} else {
return nil;
}
}
}
}
#end
you can then call them like so:
UINavigationController *myNavController = [self firstAvailableUINavigationController];
UIViewController *myViewController = [self firstAvailableUIViewController];
maybe they will help you, I hope so.
In your DropDownPickerViewController, Instead of this:
[[(AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate] navigationController] dismissModalViewControllerAnimated:NO];
Try
[self dismissModalViewControllerAnimated:NO];
I would call a method on the button's "parent" viewController and do it from there.
Update
I swapped out completely different code for pushViewController, and it is still crashing... seems like pushViewController is not the culprit. Here is what I added instead:
NSString *videoURL = [[NSString alloc] initWithFormat:#"http://www.vimeo.com/m/#/%#", videoID];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:videoURL]];
It opens up the URL in Safari, and then crashes.. wtf?
PushViewController crashes with no error in the console, but I do get an EXC_BAD_ACCESS error in Xcode. The crash doesn't happen until after the view controller has been pushed... but the view its pushing is empty... no code to mess up.
My code is below:
MainViewController.m
PlayVimeo *playTest = [[PlayVimeo alloc] initWithNibName:#"PlayVimeo" bundle:nil];
//playTest.videoID = videoID;
[self.navigationController pushViewController:playTest animated:YES];
[playTest release];
PlayVimeo.m
#import "PlayVimeo.h"
#import "SVProgressHUD.h"
#implementation PlayVimeo
#synthesize videoID, wView;
-(void)viewDidLoad {
[super viewDidLoad];
//Show loading alert
[SVProgressHUD showInView:self.view status:#"Loading Video..."];
}
-(void)viewWillAppear:(BOOL)animated {
NSLog(#"Play View Loaded!");
[self vimeoVideo];
}
-(void)vimeoVideo {
NSLog(#"Video ID: %#", videoID);
NSString *html = [NSString stringWithFormat:#"<html>"
#"<head>"
#"<meta name = \"viewport\" content =\"initial-scale = 1.0, user-scalable = no, width = 460\"/></head>"
#"<frameset border=\"0\">"
#"<frame src=\"http://player.vimeo.com/video/%#?title=0&byline=0&portrait=1&autoplay=1\" width=\"460\" height=\"320\" frameborder=\"0\"></frame>"
#"</frameset>"
#"</html>",
videoID];
NSLog(#"HTML String: %#", html);
[wView loadHTMLString:html baseURL:[NSURL URLWithString:#""]];
//Dismiss loading alert
[SVProgressHUD dismissWithSuccess:#"Playing..."];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(void)dealloc {
[super dealloc];
}
Navigation Controller Code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
[Appirater appLaunched];
return YES;
}
Console on crash:
sharedlibrary apply-load-rules all
Current language: auto; currently objective-c
(gdb)
It's likely that the culprit is
[playTest release];
Without seeing the rest of your code, I would still say that you likely need to release this after you're done with the video.
The code can not be fixed, it seems. With the UIWebView class reference, there is an example program TransWeb. Take this as base, it has a window and a navigation controller with a webview in it (in the xib). In MyViewController it reads a html-file and displays it. What you need to do is to change the main view to landscape and replace the html-code with yours. Avoid the frame-stuff.
When a user clicks a link in the present UIWebView a new view is pushed onto the navigationController's stack that contains a UIWebView. I'd like to pass the URL that was touched to this new UIWebView. How do I go about doing this?
In your UIWebView delegate:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if( navigationType == UIWebViewNavigationTypeLinkClicked ) {
YourWebViewController* vc = [[YourWebViewController alloc] initWithURL:[request URL]];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
return NO;
}
return YES;
}
Then you just need to implement the initializer in your custom viewcontroller:
- (id)initWithURL:(NSURL*)url {
self = [super init];
if( self ) {
myURL = [url retain];
}
return self;
}
Then load it at an appropriate time, like viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
[webView loadRequest:[NSURLRequest requestWithURL:myURL]];
}
Is this code correct to use with the networkActivityIndicatorVisible?
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIApplication* app2 = [UIApplication sharedApplication];
app2.networkActivityIndicatorVisible = YES;
[self loadSources]; // Loads data in table view
app2.networkActivityIndicatorVisible = NO;
}
Teo
Since NetworkActivityIndicatorVisible can be set from several points while a connection is still active, you need to track the number of calls that enable/disable it. The following UIApplication category does just that using a static variable:
// file UIApplication+NetworkActivity.h
#interface UIApplication (NetworkActivity)
- (void)showNetworkActivityIndicator;
- (void)hideNetworkActivityIndicator;
#end
// file UIApplication+NetworkActivity.m
#import "UIApplication+NetworkActivity.h"
static NSInteger activityCount = 0;
#implementation UIApplication (NetworkActivity)
- (void)showNetworkActivityIndicator {
if ([[UIApplication sharedApplication] isStatusBarHidden]) return;
#synchronized ([UIApplication sharedApplication]) {
if (activityCount == 0) {
[self setNetworkActivityIndicatorVisible:YES];
}
activityCount++;
}
}
- (void)hideNetworkActivityIndicator {
if ([[UIApplication sharedApplication] isStatusBarHidden]) return;
#synchronized ([UIApplication sharedApplication]) {
activityCount--;
if (activityCount <= 0) {
[self setNetworkActivityIndicatorVisible:NO];
activityCount=0;
}
}
}
#end
Now import UIApplication+NetworkActivity.h in your client code and call
// on connection started:
[[UIApplication sharedApplication] showNetworkActivityIndicator];
// on connection finished:
[[UIApplication sharedApplication] hideNetworkActivityIndicator];
If your concern is that the indicator blinks for only a second, you don't need a background process. Just call [self performSelector:#selector(loadSources) withObject:Nil afterDelay:0.1] so the UI thread has time to start the network indicator animation before you block the main thread.
If you're not using AFNetworking (https://github.com/AFNetworking/AFNetworking) already you can check out their network activity indicator implementation in AFNetworkingActivityIndicatorManager.
If you do choose to use this library for your network access, they handle the network activity indicator for you automatically. All you need to do is make one call in your AppDelegate to set it up, they do the rest of the work for you.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
}
An shorter solution for tracking multiple activities - again using a UIApplication category and a static variable:
#interface UIApplication (NetworkActivityIndicator)
- (void)toggleNetworkActivityIndicatorVisible:(BOOL)visible;
#end
#implementation UIApplication (NetworkActivityIndicator)
-(void)toggleNetworkActivityIndicatorVisible:(BOOL)visible {
static int activityCount = 0;
#synchronized (self) {
visible ? activityCount++ : activityCount--;
self.networkActivityIndicatorVisible = activityCount > 0;
}
}
#end
I finally solved it. I used performSelectorInBackground to execute the load data into tableView
-(void)beginLoadSources {
[self loadSources]; // Loads data in table view
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self performSelectorInBackground:#selector(beginLoadSources) withObject:nil];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
Use thins code in your ExempleUIWebView.m
before - (void)viewDidLoad
(void)webViewDidFinishLoad:(UIWebView *)webView {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[ProgressHUD dismiss];
}
and use this after - (void)viewDidLoad
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[ProgressHUD show:#"Loading Privacy Policy" Interaction:NO];