Skip to content

Commit 9db77da

Browse files
Support NativeScript (or rather: tns-ios) 3.4 #6
1 parent f60a9f6 commit 9db77da

7 files changed

Lines changed: 92 additions & 25 deletions

File tree

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Add request headers to a NativeScript WebView. Perhaps more utils later.
1414
[twitter-image]:https://img.shields.io/twitter/follow/eddyverbruggen.svg?style=social&label=Follow%20me
1515
[twitter-url]:https://twitter.com/eddyverbruggen
1616

17-
> IMPORTANT: the current version works with `tns-ios` versions prior to 3.4 (which uses `UIWebView`). Newer versions of `tns-ios` use `WKWebView`. I have an update in the works though!
17+
> Version 1.2.0 supports NativeScript-iOS 3.4 🎉 which switched from `UIWebView` to `WKWebView`. It's also backward compatible with older versions. You're welcome.
1818
1919
<img src="https://raw.githubusercontent.com/EddyVerbruggen/nativescript-webview-utils/master/media/ios-headers.png" width="300px"/>
2020

@@ -85,7 +85,7 @@ export function webViewLoaded(args: observable.EventData) {
8585
You can set this as a header, but it seems to work better setting it in a different way,
8686
so use this function if you want to override the user agent in your webview.
8787

88-
Note that on iOS this will override the user agent header in all of your webviews.
88+
> Note for NativeScript-iOS versions older than 3.4: this will override the user agent header in *all* of your webviews within your app. This is usually not an issue, but if it is: upgrade to `tns-ios` 3.4 or newer.
8989
9090
```typescript
9191
import { WebViewUtils } from 'nativescript-webview-utils';
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// You can add custom settings here
22
// for example you can uncomment the following line to force distribution code signing
3-
// CODE_SIGN_IDENTITY = iPhone Distribution
3+
// CODE_SIGN_IDENTITY = iPhone Distribution
44
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
55
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;

demo/app/main-page.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ export function webViewLoaded(args: observable.EventData) {
2828
export function webViewForUserAgentLoaded(args: observable.EventData) {
2929
const wv: WebView = <WebView>args.object;
3030
WebViewUtils.setUserAgent(wv, "My Super Duper User-Agent!");
31-
}
31+
}

demo/app/main-page.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
<StackLayout class="p-20">
44

55
<Label text="Default headers, according to https://httpbin.org/headers:" class="t-20 text-center c-black" textWrap="true"/>
6-
<WebView height="340" src="https://httpbin.org/headers"/>
6+
<WebView height="320" src="https://httpbin.org/headers"/>
77

88
<Label text="And now with custom headers:" class="t-20 text-center c-black" textWrap="true"/>
9-
<WebView id="webviewWithCustomHeaders" loaded="webViewLoaded" height="400" src="https://httpbin.org/headers"/>
9+
<WebView loaded="webViewLoaded" height="370" src="https://httpbin.org/headers"/>
1010

1111
<Label text="Set custom User Agent (on iOS this affects ALL webviews of your app)" class="t-20 text-center c-black" textWrap="true"/>
12-
<WebView id="webViewForUserAgent" loaded="webViewForUserAgentLoaded" height="400" src="https://httpbin.org/headers"/>
12+
<WebView loaded="webViewForUserAgentLoaded" height="320" src="https://httpbin.org/headers"/>
1313

1414
</StackLayout>
1515
</ScrollView>
16-
</Page>
16+
</Page>

demo/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
"nativescript": {
33
"id": "org.nativescript.demo",
44
"tns-android": {
5-
"version": "3.1.1"
5+
"version": "3.4.1"
66
},
77
"tns-ios": {
8-
"version": "3.1.0"
8+
"version": "3.4.1"
99
}
1010
},
1111
"dependencies": {
1212
"nativescript-theme-core": "^1.0.4",
1313
"nativescript-unit-test-runner": "^0.3.4",
1414
"nativescript-webview-utils": "../src",
15-
"tns-core-modules": "^3.1.1"
15+
"tns-core-modules": "~3.4.0"
1616
},
1717
"devDependencies": {
1818
"awesome-typescript-loader": "~3.1.3",
@@ -32,9 +32,9 @@
3232
"nativescript-dev-webpack": "^0.7.3",
3333
"raw-loader": "~0.5.1",
3434
"resolve-url-loader": "~2.1.0",
35-
"tns-platform-declarations": "^3.1.0",
35+
"tns-platform-declarations": "~3.4.0",
3636
"tslint": "~5.4.3",
37-
"typescript": "~2.3.0",
37+
"typescript": "~2.6.0",
3838
"webpack": "~3.2.0",
3939
"webpack-bundle-analyzer": "^2.8.2",
4040
"webpack-sources": "~1.0.1"

src/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nativescript-webview-utils",
3-
"version": "1.1.0",
3+
"version": "1.2.0",
44
"description": "Add custom headers to a NativeScript WebView. Perhaps more utils later.",
55
"main": "webview-utils",
66
"typings": "index.d.ts",
@@ -19,7 +19,7 @@
1919
"tslint": "cd .. && tslint \"**/*.ts\" --config tslint.json --exclude \"**/node_modules/**\"",
2020
"plugin.link": "npm link && cd ../demo && npm link nativescript-webview-utils && cd ../src",
2121
"plugin.tscwatch": "npm run tsc -- -w",
22-
"demo.ios": "npm i && npm run tsc && cd ../demo && tns run ios",
22+
"demo.ios": "npm i && npm run tsc && cd ../demo && tns run ios --syncAllFiles",
2323
"demo.android": "npm i && npm run tsc && cd ../demo && tns run android --syncAllFiles",
2424
"demo.reset": "cd ../demo && rimraf platforms",
2525
"plugin.prepare": "npm run tsc && cd ../demo && tns plugin remove nativescript-webview-utils && tns plugin add ../src",
@@ -47,9 +47,9 @@
4747
"homepage": "https://github.com/EddyVerbruggen/nativescript-webview-utils",
4848
"readmeFilename": "README.md",
4949
"devDependencies": {
50-
"tns-core-modules": "^3.3.0",
51-
"tns-platform-declarations": "^3.3.0",
52-
"typescript": "~2.4.0",
50+
"tns-core-modules": "~3.4.0",
51+
"tns-platform-declarations": "~3.4.0",
52+
"typescript": "~2.6.0",
5353
"prompt": "^1.0.0",
5454
"rimraf": "^2.5.0",
5555
"tslint": "^5.0.0"

src/webview-utils.ios.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
import { WebView } from "tns-core-modules/ui/web-view";
22

3+
class WebviewUtilsWKNavigationDelegateImpl extends NSObject implements WKNavigationDelegate {
4+
private headers: Map<string, string>;
5+
public static ObjCProtocols = [WKNavigationDelegate];
6+
7+
public static initWithOwnerAndHeaders(owner: WeakRef<WebView>, headers: Map<string, string>): WebviewUtilsWKNavigationDelegateImpl {
8+
const handler = <WebviewUtilsWKNavigationDelegateImpl>WebviewUtilsWKNavigationDelegateImpl.new();
9+
handler._owner = owner;
10+
handler.headers = headers;
11+
return handler;
12+
}
13+
private _owner: WeakRef<WebView>;
14+
15+
webViewDecidePolicyForNavigationActionDecisionHandler(webView: WKWebView, navigationAction: WKNavigationAction, decisionHandler: (p1: WKNavigationActionPolicy) => void): void {
16+
if (!navigationAction.request.URL) {
17+
return;
18+
}
19+
20+
let areHeadersAdded = true;
21+
this.headers.forEach((val, key) => {
22+
areHeadersAdded = areHeadersAdded && navigationAction.request.valueForHTTPHeaderField(key) === val;
23+
});
24+
25+
if (!areHeadersAdded) {
26+
decisionHandler(WKNavigationActionPolicy.Cancel);
27+
const customRequest = new NSMutableURLRequest({
28+
URL: navigationAction.request.URL,
29+
cachePolicy: NSURLRequestCachePolicy.UseProtocolCachePolicy,
30+
timeoutInterval: 60
31+
});
32+
33+
this.headers.forEach((val, key) => {
34+
if (key.toLowerCase() === "user-agent") {
35+
webView.customUserAgent = val;
36+
} else {
37+
customRequest.setValueForHTTPHeaderField(val, key);
38+
}
39+
});
40+
41+
webView.loadRequest(customRequest);
42+
} else {
43+
decisionHandler(WKNavigationActionPolicy.Allow);
44+
}
45+
}
46+
}
47+
348
export class WebViewUtils extends NSObject implements UIWebViewDelegate {
449
public static ObjCProtocols = [UIWebViewDelegate];
550

@@ -11,14 +56,34 @@ export class WebViewUtils extends NSObject implements UIWebViewDelegate {
1156
private _originalDelegate: any; // UIWebViewDelegateImpl
1257

1358
public static setUserAgent(wv: WebView, userAgent: string) {
14-
// note that overrides the useragent for ALL webviews for the app, but that's prolly not a problem
15-
NSUserDefaults.standardUserDefaults.registerDefaults(
16-
NSDictionary.dictionaryWithObjectForKey(userAgent, "UserAgent"));
59+
if (WebViewUtils.isWKWebView(wv)) {
60+
const headers: Map<string, string> = new Map();
61+
headers.set("User-Agent", userAgent);
62+
(<WKWebView>wv.ios).navigationDelegate = (<any>wv)._delegate = WebviewUtilsWKNavigationDelegateImpl.initWithOwnerAndHeaders(new WeakRef(wv), headers);
63+
} else {
64+
// note that this overrides the useragent for ALL webviews for the app, but that's prolly not a problem
65+
NSUserDefaults.standardUserDefaults.registerDefaults(
66+
NSDictionary.dictionaryWithObjectForKey(userAgent, "UserAgent"));
67+
}
1768
}
1869

1970
public static addHeaders(wv: WebView, headers: Map<string, string>) {
20-
(<any>wv)._delegate = WebViewUtils.initWithOwner(new WeakRef(wv));
21-
WebViewUtils.headers = headers;
71+
if (WebViewUtils.isWKWebView(wv)) {
72+
(<WKWebView>wv.ios).navigationDelegate = (<any>wv)._delegate = WebviewUtilsWKNavigationDelegateImpl.initWithOwnerAndHeaders(new WeakRef(wv), headers);
73+
} else {
74+
(<any>wv)._delegate = WebViewUtils.initWithOwner(new WeakRef(wv));
75+
WebViewUtils.headers = headers;
76+
}
77+
}
78+
79+
/**
80+
* NativeScript < 3.4 used UIWebView. Newer versions use WKWebView.
81+
* So one day the UIWebView code can be removed.
82+
* @param {WebView} wv
83+
* @returns {boolean}
84+
*/
85+
private static isWKWebView(wv: WebView): boolean {
86+
return wv.ios.isKindOfClass(WKWebView.class());
2287
}
2388

2489
private static initWithOwner(owner: WeakRef<WebView>): WebViewUtils {
@@ -28,8 +93,7 @@ export class WebViewUtils extends NSObject implements UIWebViewDelegate {
2893
return delegate;
2994
}
3095

31-
// TODO this is prolly different for WKWebView
32-
// You can customize your http headers here.
96+
// UIWebView delegate
3397
public webViewShouldStartLoadWithRequestNavigationType(webView: UIWebView, request: NSURLRequest, navigationType: number) {
3498
const urlString: string = request.URL.absoluteString;
3599
const isNavigationTypeBackForward = navigationType === UIWebViewNavigationType.BackForward;
@@ -57,14 +121,17 @@ export class WebViewUtils extends NSObject implements UIWebViewDelegate {
57121
return false;
58122
}
59123

124+
// UIWebView delegate
60125
public webViewDidStartLoad(webView: UIWebView) {
61126
this._originalDelegate.webViewDidStartLoad(webView);
62127
}
63128

129+
// UIWebView delegate
64130
public webViewDidFinishLoad(webView: UIWebView) {
65131
this._originalDelegate.webViewDidFinishLoad(webView);
66132
}
67133

134+
// UIWebView delegate
68135
public webViewDidFailLoadWithError(webView: UIWebView, error: NSError) {
69136
this._originalDelegate.webViewDidFailLoadWithError(webView, error);
70137
}

0 commit comments

Comments
 (0)