In my iPhone app an UITextView is containing an URL. I want to open this URL in an UIWebView instead of opening it into safari?
My UITextView contains some data along with an URL. In some cases the no. of URLs can be more than one.
Thanks
Sandy
You can follow these steps:
Tick on the following properties in UITextView taken from Xib or Storyboard.
OR write these for textview taken dynamically.
textview.delegate=self;
textview.selectable=YES;
textView.dataDetectorTypes = UIDataDetectorTypeLink;
Now write the below delegate method :
-(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
NSLog(#"URL: %#", URL);
//You can do anything with the URL here (like open in other web view).
return NO;
}
I think you are searching for that.
The UITextView has the capability to detect URLs and embed hyperlinks accordingly. You can turn that option on in:
myTextView.dataDetectorTypes = UIDataDetectorTypeLink;
Then you need to configure your app to trap this URL request and let your application handle it. I published a boilerplate class on github that does this, which might be the easiest route: http://github.com/nbuggia/Browser-View-Controller--iPhone-.
The first step is to sub-class UIApplication so you can override who gets to take action on the 'openUrl' request. Here's what that class might look like:
#import <UIKit/UIKit.h>
#import "MyAppDelegate.h"
#interface MyApplication : UIApplication
-(BOOL)openURL:(NSURL *)url;
#end
#implementation MyApplication
-(BOOL)openURL:(NSURL *)url
{
BOOL couldWeOpenUrl = NO;
NSString* scheme = [url.scheme lowercaseString];
if([scheme compare:#"http"] == NSOrderedSame
|| [scheme compare:#"https"] == NSOrderedSame)
{
// TODO - Update the cast below with the name of your AppDelegate
couldWeOpenUrl = [(MyAppDelegate*)self.delegate openURL:url];
}
if(!couldWeOpenUrl)
{
return [super openURL:url];
}
else
{
return YES;
}
}
#end
Next, you need to update main.m to specify MyApplication.h as being the bonified delegate for your UIApplication class. Open main.m and change this line:
int retVal = UIApplicationMain(argc, argv, nil, nil);
to this
int retVal = UIApplicationMain(argc, argv, #"MyApplication", nil);
Finally, you need to implement the [(MyAppDelegate*) openURL:url] method to have it do what ever you would like with the URL. Like maybe open up a new view controller with a UIWebView in it, and show the URL. You could do something like this:
- (BOOL)openURL:(NSURL*)url
{
BrowserViewController *bvc = [[BrowserViewController alloc] initWithUrls:url];
[self.navigationController pushViewController:bvc animated:YES];
[bvc release];
return YES;
}
Hopefully that should work for you.
Assuming you have the following instances, that are also added to your UIView:
UITextView *textView;
UIWebView *webView;
and textView contains the URL string, you can load the contents of the URL into webView, as follows:
NSURL *url = [NSURL URLWithString:textView.text];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[webView loadRequest:req];
Related
I am trying to learn Xcode by making a simple app.
But I been looking on the net for hours (days) and I cant figure it out how I make a button that open a UIWebView in another ViewController :S
first let me show you some code that I have ready:
I have a few Buttons om my main Storyboard that each are title some country codes like UK, CA and DK.
When I press one of those Buttons I have an IBAction like this:
- (IBAction)ButtonPressed:(UIButton *)sender {
// Google button pressed
NSURL* allURLS;
if([sender.titleLabel.text isEqualToString:#"DK"]) {
// Create URL obj
allURLS = [NSURL URLWithString:#"http://google.dk"];
}else if([sender.titleLabel.text isEqualToString:#"US"])
{
allURLS = [NSURL URLWithString:#"http://google.com"];
}else if([sender.titleLabel.text isEqualToString:#"CA"])
{
allURLS = [NSURL URLWithString:#"http://google.ca"];
}
NSURLRequest* req = [NSURLRequest requestWithURL:allURLS];
[myWebView loadRequest:req];
}
How do I make this open UIWebview on my other Viewcontroller named myWebView?
please help a lost man :D
Well, you've firstViewController already designed and coded, now you've to create secondViewController with a UIWebView binded in IB it self, also it have a setter NSString variable like strUrl that you need to pass at the time of pushing or presenting secondViewController, and assign it to UIWebView in viewDidLoad of secondViewController. See my answer about how to pass a NSString? Also UIWebView has its delegates method (What's delegate & datasource methods? - Apple Doc) Which you can use to handle URL request.
These are the delegate of UIWebView, if you'll going to use it, you need to give UIWebView delegate to self.
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
firstViewController.m
- (IBAction)ButtonPressed:(UIButton *)sender {
NSURL* allURLS;
//get your URL
secondViewControlelr *secondView=[[secondViewControlelr alloc]init];
second.urlToLoad=allURLS;
[self.navigationController pushViewController:secondView animated:YES];
}
secondViewControlelr.h
//declare url and set property
NSURL *urlToLoad;
secondViewControlelr.m
- (void)viewDidLoad
{
myWebView=[[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
[self.view addSubview:myWebView];
NSURLRequest *urlReq=[NSURLRequest requestWithURL:self.urlToLoad cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:10];
[myWebView loadRequest:urlReq];
}
I'm getting memory leaks that i can't figure out through leaks, build/analyze or overall inspection how to repair. I have a very strong notion that it's due to the loadRequest command from my UIWebview loading javascript, but I can't figure out what's wrong.
Here's my setup:
I have a tabbarcontroller that i programatically create with 4 view controllers: a table view, a mapview, another table view and a webview, respectively.
the 1st tableview shows static data.
the mapview shows annotations that when clicked populates a variable of the 4th tab, the webview, and switches to the webview to display a locally stored html/javascript file that is a 3d model
the 2nd tableview is a listing of all the same information each annotation in the mapview represents, just in table form. it has the same functionality in terms of populating the variable, switching and displaying the html/javascript file in the webview
the webview displays the html/javascript file loaded, if not it shows a UIAlertView to select one from the mapview or the list
when i finally get to executing the loadRequest() from the webview, initially everything works fine. however, when i begin to switch between tabs and view different 3d models (i.e. go to the map view click an annotation to show say model x, watch it load in the webview, then switch to the listing table and click a row to show model y (or x too) and watch it load in the webview) i start receiving memory leaks on the ipad, not the simulator. these memory leaks are almost always: General-Block 56, 1024, 8, 244 & 24 and have no responsible frames, libraries or stack traces to follow up with.
in the webview if i comment out the loadrequest line or do a loadrequest with the request object = nil, i have no memory leaks, but when i switch to using a url object that points to the local files (i even tried pointing it to google.com, which has javascript) it erupts in memory leaks.
i've attempted to do each of these:
[self.webView loadRequest:nil];
[self.webView loadHTMLString:#"" baseURL:nil];
[self.webView stopLoading];
in viewWillDisappear of my webViewController in attempt to completely clean out the webview for reuse in the future, but it doesn't seem to be doing much help. i've also attempted doing this prior to doing the loadRequest but i get the same memory leaks.
fyi, i'm running the latest xcode 4.0.2 and the ipad has the latest update, 4.3.2
from a previous post i commented on and haven't heard back from (general-block memory leak) i believe the problem has to do with the fact that webview doesn't know how to fully rid itself of the javascript when i switch views
i did a test with a simple html file with no javascript and the general-block memory leaks are gone. however, i get other cfnetwork / http message memory leaks but that's a different story and not of my concern at the moment.
below is example code of when one of the annotations on the mapView is clicked which triggers the loadModel function in the webViewController:
- (void) mapCallOutPressed: (UIView *) sender {
NSInteger selectedIndex = sender.tag;
MyLocation *selectedObject = [_mapView.annotations objectAtIndex:selectedIndex];
MyModel *model = selectedObject.model;
NSLog(#"Model selected from mapview = %#", model.description);
// Get reference to the webview from the tabBarController (viewController's index=3)
WebViewController *webViewController = [self.tabBarController.viewControllers objectAtIndex:3];
webViewController.model = model;
[webViewController loadModel];
// Switch tabs to the webView
self.tabBarController.selectedIndex = 3;
[self.tabBarController.selectedViewController viewDidAppear:YES];
below is my webViewController.h & .m:
WebViewController.h:
WebViewController : UIViewController <UIWebViewDelegate> {
UIWebView *webView;
NSString *templateRunFilePath;
MyModel *model;
NSString *templateRunTitle;
#property (nonatomic, retain) UIWebView *webView;
#property (assign) MyModel *model;
#property (nonatomic, copy) NSString *templateRunFilePath;
#property (nonatomic, copy) NSString *templateRunTitle;
-(void) loadModel;
WebViewController.m:
- (void) viewDidLoad {
[super viewDidLoad];
NSLog(#"in webview did load");
self.webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
self.webView.delegate = self;
self.webView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
self.webView.scalesPageToFit = YES;
[self.view addSubview:self.webView];
}
- (void) viewWillAppear:(BOOL)animated {
if (self.model) {
self.tabBarController.navigationItem.title = [NSString stringWithFormat: #"%# - %#", self.tabBarController.navigationItem.title, self.model.description];
}
else {
UIAlertView *msg = [[UIAlertView alloc] initWithTitle:#"No Model Selected"
message:#"Please select a model from the map or list tab to view."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[msg show];
[msg release];
}
}
- (void) loadModel {
NSString *localURLPath = [NSString stringWithFormat:#"%#/%#/%#", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];
NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[[NSUserDefaults standardUserDefaults] setInteger:0 forKey:#"WebKitCacheModelPreferenceKey"];
}
-(void)viewWillDisappear:(BOOL)animated {
NSLog(#"webview view will disappear");
[super viewWillDisappear:animated];
//[self.webView loadRequest:nil];
//[self.webView loadHTMLString:#"" baseURL:nil];
self.webView.delegate = nil;
}
- (void)dealloc {
self.webView.delegate = nil;
[self.webView release];
[super dealloc];
}
if you have any advice or corrections, i'd greatly appreciate it. i have < 1 week to figure this out and would highly thank you if you could give me any insight.
thanks!
-Mike
Mike, I am not sure whether you are doing following intentionally or by mistake?
- (void) loadModel {
[self.webView loadHTMLString:#"" baseURL:nil]; // here you are loading... or you have tried with commenting it also?
NSString *localURLPath = [NSString stringWithFormat:#"%#/%#/%#", self.templateRunFilePath, self.model.folderName, self.model.modelFileName];
NSURL *url = [NSURL fileURLWithPath:localURLPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL: url];
[self.webView loadRequest:requestObj]; // again here you are also loading?
}
According to Apple's documentation, in order to make phone call from my app, I need to implement the following protocols:
HTML link:
1-408-555-5555
Native application URL string:
tel:1-408-555-5555
However, upon completion of a phone call initiated from an HTML link inside a UIWebView, I am redirected right back to my application. But upon completion of a phone call made from a native application URL string, my iphone stays in the iphone's regular phone application, and if I want to return to my application I have to do so manually.
As far as I can tell from reading what others have said, there is no way to change this behavior.
Here is my question:
Is it true that it's impossible
to return to an application after
making a phone call from a native
application URL string?
Would there be any downside to
implementing a UIWebView instead of
a UILabel in situations where I
really wanted the user to be
redirected back to my application
after completing a phone call?
The simplest way seems to be:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"telprompt:0123456789"]];
You will get a prompt and your app will regain focus after the call is finished.
Behavior does differ between calling -[UIApplication openURL:] with a tel: URL, and clicking a link to the same URL in a UIWebView.
Using a UIWebView instead of a UILabel might have some downsides, but you don't have to actually display the UIWebView to get its tel URL handling behavior. Instead, just load a tel URL request in an instance of UIWebView without adding it to your view hierarchy.
For example:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface PhoneCaller : NSObject
{
#private
UIWebView *webview;
}
- (void)callTelURL:(NSURL *)url;
#end
#implementation
- (id)init
{
self = [super init];
if (self)
{
webview = [[UIWebView alloc] init];
}
return self;
}
- (void)callTelURL:(NSURL *)url
{
[webview loadRequest:[NSURLRequest requestWithURL:url]];
}
- (void)dealloc
{
[webview release];
[super dealloc];
}
#end
Allow me to simplify a bit. All you need is this little snippet:
UIWebView *callWebview = [[UIWebView alloc] init];
NSURL *telURL = [NSURL URLWithString:#"tel:number-to-call"];
[callWebview loadRequest:[NSURLRequest requestWithURL:telURL]];
which I got here.
*Recently tested successfully on iOS 5.0.
The Eric's Brotto method still works in 5.1. You have to add the webview to the main view before the loadRequest, like this:
NSString *cleanedString = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet characterSetWithCharactersInString:#"0123456789-+()"] invertedSet]] componentsJoinedByString:#""];
NSString *escapedPhoneNumber = [cleanedString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *telURL = [NSURL URLWithString:[NSString stringWithFormat:#"tel://%#", escapedPhoneNumber]];
UIWebView *mCallWebview = [[UIWebView alloc] init] ;
[self.view addSubview:mCallWebview];
[mCallWebview loadRequest:[NSURLRequest requestWithURL:telURL]];
(I added a phone number cleaner, to delete any non-number char that blocks this method)
I'm making an iphone app...can I get the source from it in objective-c?
Thanks!
Elijah
You can get anything from the web view that JavaScript can return using stringByEvaluatingJavaScriptFromString:. Try something along the lines of
document.lastChild.outerHTML
The document will likely have two child nodes; the first will be the DOCTYPE, and the second the <html> element.
If you need to get the contents of the current URL in your web view you could have something like this in a UIViewController. I didn't compile this code, so there may be some syntax errors, but this should be a solid starting point for your problem.
#interface aViewController : UIViewController <UIWebViewDelegate>
UIWebView *webView;
NSString *htmlSource;
#end
#implementation aViewController
-(void) viewDidLoad {
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
self.webView = [[UIWebView alloc] initWithFrame:webFrame];
self.webView.delegate = self;
NSURL *aURL = [NSURL URLWithString:#"http://www.myurl.com"];
NSURLRequest *aRequest = [NSURLRequest requestWithURL:aURL];
//load the index.html file into the web view.
[self.webView loadRequest:aRequest];
}
//This is a delegate method that is sent after a web view finishes loading content.
- (void)webViewDidFinishLoad:(UIWebView *)webView{
NSLog(#"finished loading");
self.htmlSource = [[NSString alloc] initWithData:[[webView request] HTTPBody] encoding:NSASCIIStringEncoding];
}
#end
I got a pdf viewer in a uiwebview, from Daniel Barry http://github.com/danberry/PDF-Viewer and it works really well, it displays a pdf doc that you can scroll up and down.
Now I would like to display just one page at the time and also have a menu underneat the pdf page with a prev and next button. Can anybody help a newbe to figure out how?
Thanks!
#import "PDFViewController.h" // PDF View Controller
#implementation PDFViewController
// Synthesize UI Element properties
#synthesize webView;
// Synthesize Variable properties
#synthesize pdfURL;
#pragma mark -
#pragma mark UIViewController methods
- (void)viewDidLoad {
[super viewDidLoad];
pdfURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"stuff pdf" ofType:#"pdf"]];
[webView loadRequest:[NSURLRequest requestWithURL:pdfURL]];
webView.transform = CGAffineTransformScale( webView.transform, 1.00, 1.00 );
}
#pragma mark -
#pragma mark Memory Management
- (void)dealloc {
[webView release];
[pdfURL release];
[super dealloc];
}
#end
I think a webview should show PDFs by using a default request, no need to have a new implementation?
Anyways... There are 2 methods you could check out and link to your prev and next button
- (void)goBack:(id)sender
{
if ([webView canGoBack]) {
[webView goBack];
}
}
- (void)goForward:(id)sender
{
if ([webView canGoForward]) {
[webView goForward];
}
}
Here is the documentation of UIWebView where the methods are explained in detail: http://developer.apple.com/iphone/library/documentation/uikit/reference/UIWebView_Class/Reference/Reference.html
EDIT: Oh I think, I first misunderstood your question...
Just create an Array of the PDF URLs that you want to load. Create a counter variable that will hold the index value of the currently opened PDF.
And finally similar to the methods above create a forward and backward method and link them to the prev and next buttons. In those methods you increment or decrement the counter by 1 and load the appropriate index from the array [array objectAtIndex:counter] so the next or previous PDF is opened.
If you need more help, let me know...
ok im gonna post this as another answer...
In the header file add
NSArray *arrURLs;
NSInteger *currentIndex;
and make the array a property (retain), synthesize it in the .m file, also release it in dealloc.
In - (void)viewDidLoad initalize the array with all the URLs and set the currentIndex to 0.
arrUrls = [[NSArray alloc] initWithObjects:#"url", #"url", ..., nil];
currentIndex = 0;
add two methods that you call something like prevPage and nextPage and link them to your buttons. In those methods you do something like...
// next page
currentIndex += 1;
NSString *str = [arrUrls objectAtIndex:currentIndex];
NSURL *url = [NSURL URLWithString:str];
[webView loadRequest:[NSURLRequest requestWithURL:url]];
I would probably create another method where you set the currentIndex and check if it is in the correct bounds (e.g. should not be smaller than 0 and must be smaller than the length of the array). Than you can change the first line and let the method call handle the in/decrementing of the variable.
hope this helps.