GithubHelp home page GithubHelp logo

eddyverbruggen / nativescript-webview-utils Goto Github PK

View Code? Open in Web Editor NEW
20.0 3.0 17.0 2.22 MB

🕸Add request headers to a NativeScript WebView. Perhaps more utils later.

License: Apache License 2.0

Shell 8.45% TypeScript 91.55%
nativescript nativescript-plugin webview headers request-header

nativescript-webview-utils's Introduction

NativeScript WebView Utils plugin

Add request headers to a NativeScript WebView. Perhaps more utils later.

Build Status NPM version Downloads Twitter Follow

For NativeScript versions older than 7, use a plugin version older than 4.0.0.

Installation

From the command prompt go to your app's root folder and execute:

tns plugin add nativescript-webview-utils

Usage

Demo app (XML + TypeScript)

You can run the demo app from the root of the project by typing npm run demo.ios or npm run demo.android.

API

addHeaders

If you're loading a page that requires you to send additional headers (for security perhaps), this function allows you to dynamically inject those to any links within the webview.

NativeScript with Angular

<WebView [src]="someSource" (loaded)="webViewLoaded($event)"></WebView>
import { EventData } from "tns-core-modules/data/observable";
import { WebView } from "tns-core-modules/ui/web-view";
import { WebViewUtils } from "nativescript-webview-utils";

export class MyComponent {
  someSource: string = "https://httpbin.org/headers";

  webViewLoaded(args: EventData): any {
    const webView: WebView = <WebView>args.object;
    const headers: Map<string, string> = new Map();
    headers.set("Foo", "Bar :P");
    headers.set("X-Custom-Header", "Set at " + new Date().toTimeString());
    WebViewUtils.addHeaders(webView, headers);
  }
}

NativeScript with XML

<WebView id="webviewWithCustomHeaders" loaded="webViewLoaded" height="360" src="https://httpbin.org/headers"/>
// then add a few headers in the associated JS / TS file like this:
import { WebViewUtils } from 'nativescript-webview-utils';
import { WebView } from 'tns-core-modules/ui/web-view';
import * as observable from 'tns-core-modules/data/observable';

export function webViewLoaded(args: observable.EventData) {
  const wv: WebView = <WebView>args.object;
  const headers: Map<string, string> = new Map();
  headers.set("Foo", "Bar :P");
  headers.set("X-Custom-Header", "Set at " + new Date().toTimeString());
  WebViewUtils.addHeaders(wv, headers);
}

setUserAgent

This method was removed in 2.0.0 because it caused bugs when addHeaders was used as well.

You should now use addHeaders and set the User-Agent header:

import { WebViewUtils } from 'nativescript-webview-utils';
import { WebView } from 'tns-core-modules/ui/web-view';
import * as observable from 'tns-core-modules/data/observable';

export function webViewForUserAgentLoaded(args: observable.EventData) {
  const wv: WebView = <WebView>args.object;
  const headers: Map<string, string> = new Map();
  headers.set("User-Agent", "My Awesome User-Agent!"); // this line!
  WebViewUtils.addHeaders(wv, headers);
}

Credits

Quite some code was borrowed from this repo.

nativescript-webview-utils's People

Contributors

eddyverbruggen avatar logikgate avatar nathanwalker avatar ractoon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

nativescript-webview-utils's Issues

Additional page asset loads do not include custom headers

Which platform(s) does your issue occur on?

  • Reproduced on iOS device (iPhone 6: 12.3.1)
  • iOS emulator (12.1)

Please, provide the following version numbers that your issue occurs with:

(using the provided demo app tagged in 3.0.1)

  • tns version: 5.3.4
  • Cross-platform modules: 5.3.2
  • Runtime(s):
    • ios: 5.0.0
    • android: 5.0.0
  • Plugin(s):
    "devDependencies": {
    "tns-core-modules": "~5.3.1",
    "tns-platform-declarations": "~5.3.1",
    "typescript": "~2.8.0",
    "tslint": "^5.0.0"
    },

Please, tell us how to recreate the issue in as much detail as possible.

If I load a page (https://some.tld/index.html) as the target of the WebView and that page contains links to other assets (say img1.png and img2.png) the GET request for index.html correctly includes the custom headers but the requests for img1.png and img2.png do not include the custom headers. The User-Agent is correctly set in ALL 3 requests.

Is there any code involved?

Sample server header output from my example from above just redirecting the demo app target URL:

Host: some.tld
X-Custom-Header: Set at 18:57:00 GMT-0600 (MDT)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
User-Agent: My Awesome User-Agent!
Accept-Language: en-us
appname: Bar :P
Accept-Encoding: br, gzip, deflate

127.0.0.1 - - [01/Jul/2019 18:57:02] "GET /index.html HTTP/1.1" 200 -

Host: some.tld
Accept: image/png,image/svg+xml,image/;q=0.8,video/;q=0.8,/;q=0.5
User-Agent: My Awesome User-Agent!
Accept-Language: en-us
Referer: https://some.tld/index.html
Accept-Encoding: br, gzip, deflate

127.0.0.1 - - [01/Jul/2019 18:57:02] "GET /img1.png HTTP/1.1" 200 -

Host: some.tld
Accept: image/png,image/svg+xml,image/;q=0.8,video/;q=0.8,/;q=0.5
User-Agent: My Awesome User-Agent!
Accept-Language: en-us
Referer: https://some.tld/index.html
Accept-Encoding: br, gzip, deflate

127.0.0.1 - - [01/Jul/2019 18:57:02] "GET /img2.png HTTP/1.1" 200 -

Error while loading webview

Facing issue while loading upi://pay in webview.
Is there any way to load the upi://pay successfully in webview?

My package.json:

"description": "NativeScript Application",
"license": "SEE LICENSE IN ",
"repository": "",
"scripts": {
"lint": "tslint "src/**/*.ts""
},
"dependencies": {
"@angular/animations": "~10.1.0",
"@angular/common": "~10.1.0",
"@angular/compiler": "~10.1.0",
"@angular/core": "~10.1.0",
"@angular/forms": "~10.1.0",
"@angular/platform-browser": "~10.1.0",
"@angular/platform-browser-dynamic": "~10.1.0",
"@angular/router": "~10.1.0",
"@nativescript/angular": "~10.1.0",
"@nativescript/core": "~7.0.0",
"@nativescript/firebase": "^11.0.0",
"@nativescript/social-share": "^2.0.4",
"@nativescript/theme": "~2.3.0",
"@nativescript/webpack": "3.0.0",
"@nstudio/nativescript-cardview": "^2.0.0",
"@nstudio/nativescript-loading-indicator": "^4.0.0",
"@nstudio/nativescript-snackbar": "^2.1.0",
"nativescript-appversion": "^1.4.2",
"nativescript-exit": "^1.0.1",
"nativescript-fancyalert": "^3.0.9",
"nativescript-image-cache": "^1.1.6",
"nativescript-permissions": "^1.3.8",
"nativescript-phone": "^1.4.1",
"nativescript-sqlite": "^2.6.4",
"nativescript-theme-core": "~1.0.6",
"nativescript-toasts": "^1.0.3",
"nativescript-ui-sidedrawer": "~9.0.0",
"nativescript-webview-utils": "^4.0.0",
"reflect-metadata": "~0.1.12",
"rxjs": "^6.6.0",
"rxjs-compat": "^6.4.0",
"zone.js": "~0.11.1"
},
"devDependencies": {
"@angular/compiler-cli": "~10.1.0",
"@nativescript/android": "7.0.1",
"@nativescript/ios": "7.0.2-rc1",
"@nativescript/webpack": "~3.0.0",
"@ngtools/webpack": "~10.1.0",
"codelyzer": "~6.0.0",
"node-sass": "^4.14.1",
"tslint": "~6.1.3",
"typescript": "~3.9.0"
},

Setting multiple cookies in header not possible

Which platform(s) does your issue occur on?

  • Both

Please, provide the following version numbers that your issue occurs with:

Not relevant as this is a code related thing.

Please, tell us how to recreate the issue in as much detail as possible.

As the headers is in a Map<string, string> it is not possible to use the header parameter Set-Cookie more than for one cookie. I need to set more than one cookie when doing a request and it's not possible as of how a Map works. To be able to set more than one cookie the syntax in a HTTP header is:
Set-Cookie: cookie1=value1
Set-Cookie: cookie2=value2
etc

By the nature of a Map<string, string> there is no way to set more than one and one only value. A way of doing this could be to use a method named WebViewUtils.addHeaders(wv: WebView, headers: Map<string, string[]>) and that in a non destructive manner just adds the the array of header values with the header param name one for each value. Non-destructive in that manner that addHeaders of whatever type can be called multiple times and in that manner build up the total payload of headers.

Is there any code involved? Yes!

// This code does not work. Server will only retrieve cookie2 but both must be included to make a successful request.
const headers: Map<string, string> = new Map();
headers.set('Set-Cookie', 'cookie1=value1');
headers.set('Set-Cookie', 'cookie2=value2');
WebViewUtils.addHeaders(webView, headers);

Remove setUserAgent, and integrate behavior with addHeaders

If users need to set both the User-Agent header, and other headers as well, then problems may occur because how that works internally in different browsers. So I've decided to remove setUserAgent and provide a sample how to set it as a custom header (and changed the plugin to handle it properly).

LoadStarted WebView event doesn't trigger on Android

I am using [loadStarted] and [loadFinished] events in a Webview in NativeScript/Angular, among other things, to start and stop a spinner. On my iPhone both events are triggered as soon as navigation starts and ends. On my Android phone the loadStarted event isn't triggered causing the spinner to malfunction. Looks like only links with tel:, mailto: and loc: trigger the [loadStarted] event.

In node module [webview-utils.android.js], function [onPageStarted], line 47 there is this If statement: if (!isHttpRequest || ++this.startEventCount === 1) The ++ increments this.startEventCount while testing === 1 which will only be true the first time a pageLoad starts. In my opinion this causes the loadStarted event to be called only once (unless the url starts with [tel:, mailto: or loc:]) Having fixed this locally, I noticed that the loadStarted event is triggered too late. Showing the spinner only a few milliseconds before the webpage finishes loading.

Non-trigger and too late trigger of [loadStarted] both don't work for my App.
Are there solutions to these problems?

XML:

<ActionBar #webviewActionbar title="Facilitor" flat="true">
    <ActionItem (tap)="onQrScanTap()" ios.position="right" ios.systemIcon="15" android.systemIcon="ic_menu_camera">
    </ActionItem>
</ActionBar>
<GridLayout rows="*">
    <WebView row="0" #loginView (loaded)="webviewLoaded($event);" (loadStarted)="webviewTrigger($event)" (loadFinished)="onLoadFinished($event)" (doubleTap)="onDoubleTap($event)" (swipe)="onSwipe($event)" [src]="webViewSrc" ></WebView>
    <TextField row="0" [(ngModel)]="registerModel.push_action" #pushActionModel="ngModel" autocorrect="false"
    autocapitalizationType="none" [visibility]="'collapse'" (textChange)="navigateToAction()"></TextField>
    <ActivityIndicator (loaded)="onSpinnerLoaded($event)" rowSpan="2" [busy]="isBusy" (busyChange)="onBusyChanged($event)" width="100" height="100"></ActivityIndicator>
</GridLayout>

TypeScript:

  private onLoadFinished(args: any) {
    console.log("== onLoadFinished ==");
    this.isBusy = false;
  }
  private webviewTrigger(args: any) {
    console.log("== webviewTrigger ==");
    var webView: WebView = <WebView>args.object;
    console.log(webView);
    // get location
    if (args.url.startsWith('loc:')) {
      let arr = args.url.split(":");
      this.registerModel.push_action = this.registrationService.composeUrl() + arr[1] + "?longitude=" + this.lastLocation.longitude + "&latitude=" + this.lastLocation.latitude;
      this.navigateToAction();
      webView.reload();
      return;
    // handle mailto: and tel:
    } else if (args.url.startsWith('mailto:') || args.url.startsWith('tel:')) {
      utils.openUrl(args.url);
      webView.reload();
      return;
    }
    // start spinner
    this.isBusy = true;
  }

Terminal log after tapping some links:

JS: == onNavigatingTo ==
chromium: [INFO:library_loader_hooks.cc(51)] Chromium logging enabled: level = 0, default verbosity = 0
JS: == webviewLoaded ==
JS: WebView(44)
JS: == setHTTPHeader ==
JS: == onSpinnerLoaded ==
JS: == onNavigatedTo ==
JS: == webviewTrigger ==
JS: WebView(44)
JS: indicator.busy changed to: true
JS: ===Location===
JS: == onLoadFinished ==
JS: indicator.busy changed to: false
JS: == onLoadFinished ==
JS: == onLoadFinished ==
JS: == onLoadFinished ==

How to resolve WebView HTTP 500 error code

Make sure to check the demo app(s) for sample usage

Make sure to check the existing issues in this repository

If the demo apps cannot help and there is no issue for your problem, tell us about it

Please, ensure your title is less than 63 chara cters long and starts with a capital
letter.

Which platform(s) does your issue occur on?

  • iOS/Android/Both
  • iOS/Android versions
  • emulator or device. What type of device?

Please, provide the following version numbers that your issue occurs with:

  • CLI: (run tns --version to fetch it)
  • Cross-platform modules: (check the 'version' attribute in the
    node_modules/tns-core-modules/package.json file in your project)
  • Runtime(s): (look for the "tns-android" and "tns-ios" properties in the package.json file of your project)
  • Plugin(s): (look for the version numbers in the package.json file of your
    project and paste your dependencies and devDependencies here)

Please, tell us how to recreate the issue in as much detail as possible.

Describe the steps to reproduce it.

Is there any code involved?

  • provide a code example to recreate the problem
  • (EVEN BETTER) provide a .zip with application or refer to a repository with application where the problem is reproducible.

Mixed Content Handling

I facing an mix-content issue where a navigating from https to http.
I using webview-util to inject the app token as in header.

How can we allow mix-content in the webview?

nativescript-webview-utils is not working in android/ios

I tried to run the app in both android/ios got the error like this WebViewUtils.addHeaders is not a function,undefined...

JS code:
var WebView =require("tns-core-modules/ui/web-view");
var WebViewUtils=require("nativescript-webview-utils");

function webViewLoaded(args) {
var wv = args.object;
// as a bonus, hide those ugly Android zoomcontrols
if (wv.android) {
wv.android.getSettings().setBuiltInZoomControls(false);
}
var headers = new Map();
headers.set("Foo", "Bar :P");
headers.set("X-Custom-Header", "Set at " + new Date().toTimeString());
WebViewUtils.addHeaders(wv, headers);
}
exports.webViewLoaded = webViewLoaded;

Exception: `Calling js method onReceivedError failed`

Which platform(s) does your issue occur on?

  • Android
  • system-images;android-30;google_apis;arm64-v8a

Please, provide the following version numbers that your issue occurs with:

  • CLI: 8.1.5
  • Cross-platform modules:
    (…you mean dependencies?)
  "dependencies": {
    "@nativescript/core": "7.0.3",
    "@nativescript/firebase": "11.0.0",
    "@nativescript/local-notifications": "5.0.0",
    "@nativescript/theme": "2.5.0",
    "nativescript-dna-deviceinfo": "2.4.3",
    "@nativescript/localize": "5.0.2",
    "nativescript-webview-interface2": "1.4.7",
    "nativescript-webview-utils": "3.0.1"
  },
  "devDependencies": {
    "@nativescript/android": "7.0.0",
    "@nativescript/ios": "7.0.0",
    "@nativescript/types": "7.0.3",
    "@nativescript/webpack": "3.0.4",
    "nativescript-remote-builds": "1.1.1",
    "typescript": "3.9.7"
  },
  • Runtime(s): no entries in my package.json
  • Plugin(s): see above

Please, tell us how to recreate the issue in as much detail as possible.

Started App, opened chrome://inspect/#devices in Chrome on Computer. Clicked inspect on the emulator entry. App inside emulator crashed.

Exception:

Calling js method onReceivedError failed 
Error: JNI Exception occurred (SIGABRT).
=======
Check the 'adb logcat' for additional information about the error.
=======

StackTrace
push.../node_modules/nativescript-webview-utils/webview-utils.js.WebViewUtils.onReceivedError(file:///data/data/de.emscon.plano/files/app/vendor.js:76026:46)
    at com.tns.Runtime.callJSMethodNative(Native Method)
    at com.tns.Runtime.dispatchCallJSMethodNative(Runtime.java:1302)
    at com.tns.Runtime.callJSMethodImpl(Runtime.java:1188)
    at com.tns.Runtime.callJSMethod(Runtime.java:1175)
    at com.tns.Runtime.callJSMethod(Runtime.java:1153)
    at com.tns.Runtime.callJSMethod(Runtime.java:1149)
    at com.tns.gen.android.webkit.WebViewClient_vendor_75960_28_WebViewUtils.onReceivedError(WebViewClient_vendor_75960_28_WebViewUtils.java:72)
    at g9.handleMessage(chromium-TrichromeWebViewGoogle6432.apk-stable-447211484:124)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7356)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Is there any code involved?

Very simple app:

<Page class="page"
	loaded="pageLoaded"
    xmlns="http://schemas.nativescript.org/tns.xsd"
    backgroundSpanUnderStatusBar="true"
    backgroundColor="#cd7415"
    iosOverflowSafeAreaEnabled="false"
>
    <GridLayout>
        <WebView
            iosOverflowSafeAreaEnabled="true"
            row="1" loaded="onWebViewLoaded" id="webView"
        >
    	</WebView>
    </GridLayout>
</Page>

Deprecated API usage

Platform: iOS
Version: latest

ITMS-90809: Deprecated API Usage - New apps that use UIWebView are no longer accepted. Instead, use WKWebView for improved security and reliability. Learn more (https://developer.apple.com/documentation/uikit/uiwebview).

Apple refuses by default every new application with references to UIWebView APIs.
See webview-utils.ios.ts

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.