Is there a way to disable interactions on a webview?
So that the user can not go any further than the webview that is loaded?
EDIT:
Disabling UserInteractions is not a solution because the website still has to be scrollable.
Implement the WKNavigationDelegate protocol:
#interface ViewController () <WKNavigationDelegate>
Set your WKWebView's navigationDelegate property:
self.wkWebView.navigationDelegate = self;
Then implement the policy for the URL(s) that you want to restrict:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if ([navigationAction.request.URL.absoluteString containsString:#"somedomain.com/url/here"]) {
decisionHandler(WKNavigationActionPolicyAllow);
}
else {
decisionHandler(WKNavigationActionPolicyCancel);
}
}
The WKNavigationDelegate solution only prevents the user from following links. I also have form controls that I want to prevent interaction with, while still allowing the page to be scrolled. Eventually I figured out that this could be achieved by disabling the subviews of the web view's scroll view:
Swift
self.webView.scrollView.subviews.forEach { $0.isUserInteractionEnabled = false }
Objective-C
for (UIView *subview in self.webView.scrollView.subviews)
{
subview.userInteractionEnabled = NO;
}
First, you have to give the delegate to your webkit then add below code.
Swift 5.0
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
Activity.stopAnimating()
let javascriptStyle = "var css = '*{-webkit-touch-callout:none;-webkit-user-select:none}'; var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(css)); head.appendChild(style);"
webView.evaluateJavaScript(javascriptStyle, completionHandler: nil)
}
What this code will do, we add programmatically css that will disable interaction in webview
These javascript lines will disable long presses and link touches by overriding the HTML. Frame based things like embedded youtube videos will still work.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.documentElement.style.webkitUserSelect='none'")
webView.evaluateJavaScript("document.documentElement.style.webkitTouchCallout='none'")
webView.evaluateJavaScript("var elems = document.getElementsByTagName('a'); for (var i = 0; i < elems.length; i++) { elems[i]['href'] = 'javascript:(void)'; }")
}
You can do it as follow.
//-----------------------------------------------------------------------
#pragma mark - UIWebView Methods
//-----------------------------------------------------------------------
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
return YES;
}
//----------------------------------------------------------------
- (void)webViewDidStartLoad:(UIWebView *)webView {
//disable user interaction
}
//----------------------------------------------------------------
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//enable user interaction
}
//----------------------------------------------------------------
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
//enable user interaction
}
Related
I am implementing the web view through react-native. Therefore, I use the react-native-webview library. However, "window.open" and "window.close" are not implemented in the react-native-webview.
I need to apply that part of the code for social login. So I found the swift code document. However, I don't know how to change this document to an objective-c code.
object-c partial code of react-native-webview
swift document
// webView list management
var webViews = [WKWebView]()
...
func webView(_ webView: WKWebView,
createWebViewWith configuration: WKWebViewConfiguration,
for navigationAction: WKNavigationAction,
windowFeatures: WKWindowFeatures
) -> WKWebView? {
guard let frame = self.webViews.last?.frame else {
return nil
}
//Creating and returning a web view creates a parent relationship with the current web view.
return createWebView(frame: frame, configuration: configuration)
}
/// ---------- popup close ----------
func webViewDidClose(_ webView: WKWebView) {
destroyCurrentWebView()
}
// Examples of Web View Generation Methods
func createWebView(frame: CGRect, configuration: WKWebViewConfiguration) -> WKWebView {
let webView = WKWebView(frame: frame, configuration: configuration)
// set delegate
webView.uiDelegate = self
webView.navigationDelegate = self
// add view
self.view.addSubview(webView)
self.webViews.append(webView)
return webView
}
// Examples of webview deletion methods
func destroyCurrentWebView() {
// remove from webview lists and screens
self.webViews.popLast()?.removeFromSuperview()
}
How can I apply this code to suit the react-native-webview?
EDIT
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
WKWebView *popUpWebView = [[WKWebView alloc] initWithFrame: navigationAction.targetFrame configuration: configuration];
popUpWebView.uiDelegate = self;
popUpWebView.navigationDelegate = self;
[_webView addSubview:popUpWebView];
return nil;
}
- (void)webViewDidClose:(WKWebView *)webView {
[_webView removeFromSuperview];
}
I looked at the document and changed it as follows. However, an error occurs when building. I don't know what the problem is.
As I mentioned in my comments, I am not sure if this will work for React Native but this Obj-C code is the same as your swift code and should compile
In your .h file
Your .h file will probably need to be the same as RNCWebView.h and you might need to remove anything unwanted / unused
In your .m file
Similarly, your .m will be similar to RNCWebView.m and remove what you don't use.
Then as per your swift code, these are the updated Obj C versions of those functions
- (WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction
windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
if ([webViews count] == 0) {
return nil;
}
WKWebView *currentWebView = [webViews lastObject];
WKWebView *popUpWebView = [[WKWebView alloc] initWithFrame: currentWebView.frame
configuration: configuration];
popUpWebView.UIDelegate = self;
popUpWebView.navigationDelegate = self;
[webView addSubview:popUpWebView];
return popUpWebView;
}
- (void)webViewDidClose:(WKWebView *)webView
{
[webView removeFromSuperview];
}
Update
If the webViews variable from the original swift code is unused / not needed, you probably need to update the webView createWebViewWithConfiguration as follows:
- (WKWebView *)webView:(WKWebView *)webView
createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
forNavigationAction:(WKNavigationAction *)navigationAction
windowFeatures:(WKWindowFeatures *)windowFeatures
{
if (!navigationAction.targetFrame.isMainFrame) {
[webView loadRequest:navigationAction.request];
}
WKWebView *popUpWebView = [[WKWebView alloc] initWithFrame: webView.bounds
configuration: configuration];
popUpWebView.UIDelegate = self;
popUpWebView.navigationDelegate = self;
[webView addSubview:popUpWebView];
return popUpWebView;
}
Finally, just to clarify:
The header does not need to be the same as mine, I just gave you an example if you were subclassing a UIViewController. You probably need to follow the header and implementation file defined here
My goal was to convert your swift code into Obj C code that would compile, I cannot say if it is right for React Native however.
How i can remove or hide a page counter from WKWebview when load a PDF file?
I tried the solutions that are on this link (using iOS 13.3, Swift 4.2.), but they don't work.
With the help of a friend, we found a solution.
In the delegate method, we can hide the UIView which contains the page counter:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
hidePDFPageCount(webView)
}
func hidePDFPageCount(_ webView: WKWebView){
guard let last = webView.subviews.last else {
return
}
last.isHidden = true
}
Objective-C version, tested on iOS 14:
#pragma mark - WKNavigationDelegate
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
UIView *lastView = webView.subviews.lastObject;
if (lastView != nil && ![lastView isKindOfClass:[UIScrollView class]]) {
lastView.hidden = YES;
}
}
Compared to the accepted answer I had to add:
![lastView isKindOfClass:[UIScrollView class]]
Because the last view is not always the page counter.
I am loading a url in UIWebView in iOS. the url contains a button. I want to call a objective C method, when i click on this button. Please help.
This is source code
NSString *strUrl = #"<html><body><button type=\"button\" id=\"success_id\" style=\"width:200px;margin:0px auto;text-align:center; background:#1B2F77;color:#fff;padding:10px;font-size:10px;border:0px;\" name=\"continue\" onclick=\"ok.performClick();\">Continue</button></body></html>";
[_tempWebView loadHTMLString:strUrl baseURL:nil];
I want to load this string to UIWebview and When I click on button , then I want to open my own viewcontroller.
You need to do three things:
Override shouldStartLoadWithRequest delegate method of UIWeBView.
shouldStartLoadWithRequest method returns a bool value so return false, then it will not load the link.
Inside this method write whatever functionality you want to perform.
If it is your page, communicate with app via JavaScript otherwise you can override shouldStartLoadWithRequest method and check if this specific request is called
some code:
- (BOOL)isItThatButtonEvent:(NSURLRequest *)req {
if([req.URL.absoluteString isEqualString:#"that.specific.url.or.some.other.way.to.check.that"]) {
return YES;
}
return NO;
}
#pragma mark UIWebViewDelegate
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if([self isItThatButtonEvent:request]) {
[self methodThatOpensYourViewController];
return NO;
}
return YES;
}
I'm removing content of the webView in the webViewDidFinishLoad. The problem is it first loads the page and shows all the content and then you will see the content I'm removing disappear. I would like it so that the user doesn't see anything disappear so the content should never been shown to the user.
This is my method :
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
NSString* script = [NSString stringWithFormat:#"document.getElementById('menu').style.display='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:script];
NSLog(#"gets");
}
The trick is use of isLoading property.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if(!webView.isLoading){
//Has completely stopped..
}
}
Use webview.hidden = YES till the time you dont want to see the data and then set it as no again
You can use the UIWebView Delegate methods as shown below.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
webView.hidden = YES;
return YES;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
webView.hidden = NO;
}
Isn't the same thing work in viewDidLoad ?
-(void)viewDidLoad{
NSString* script = [NSString stringWithFormat:#"document.getElementById('menu').style.display='none';"];
[self.webView stringByEvaluatingJavaScriptFromString:script];
NSLog(#"gets");
}
I have UIView and UIWebView on screen. When I click on text field in website, web view content is going up. How could I force UIView to move as well then?
You can subscribe to either the UIKeyboardWillShowNotification or the UIKeyboardDidShowNotification, and move your UIView when you receive the notification. This process is described here:
Text, Web, and Editing Programming Guide for iOS: “Moving Content That Is Located Under the Keyboard”
Maybe this helps: I didn't want the UIWebView to scroll at all, including when focusing on a textfield.
You have to be the delegate of the UIWebView:
_webView.scrollView.delegate = self;
And then add this method
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
scrollView.contentOffset = CGPointZero;
}
UIWebView has a callback:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
This is triggered whenever a new URL request is about to load. From javascript, you could trigger a new request URL on the onfocus event of the tag, with a custom schema like:
window.location = "webViewCallback://somefunction";
Here's a script to put your custom event inside any html page to load.
You'll have to get the whole HTML before loading it to the UIWebView like this:
NSString *html = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"your URL"] encoding:NSUTF8StringEncoding error:nil];
Then insert the following inside the HTML text in a appropriate place:
<script>
var inputs = document.getElementsByTagName('input');
for(int i = 0; i < inputs.length; i++)
{
if(inputs[i].type = "text")
{
inputs[i].onfocus += "javascript:triggerCallback()";
}
}
function triggerCallback()
{
window.location = "webViewCallback://somefunction";
}
</script>
Then, on the callback you should do something like this:
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( [[inRequest URL] scheme] == #"webViewCallback" ) {
//Change the views position
return NO;
}
return YES;
}
That's it. Hope it helps.
Wow, I had the same problem few days ago, it was really annoying. I figured out that window.yPageOffset is changing, but as far as I know there aren't any events to bind when it changes. But maybe it will help you somehow. ;-)
I think you overwrote scrollViewDidScroll wrong.
You need to implement custom class for UIWevView and overwrite scrollViewDidScroll:
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[super scrollViewDidScroll:scrollView];
[((id<UIScrollViewDelegate>)self.delegate) scrollViewDidScroll:scrollView];
}