cronapp-cordova-plugin-ionic-webview 4.4.0-RC7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,645 @@
1
+ /*
2
+ Copyright 2015 Google Inc. All rights reserved.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+ package com.ionicframework.cordova.webview;
17
+
18
+ import android.content.Context;
19
+ import android.net.Uri;
20
+ import android.os.Build;
21
+ import android.util.Log;
22
+ import android.webkit.WebResourceRequest;
23
+ import android.webkit.WebResourceResponse;
24
+
25
+ import org.apache.cordova.ConfigXmlParser;
26
+
27
+ import java.io.IOException;
28
+ import java.io.InputStream;
29
+ import java.net.HttpURLConnection;
30
+ import java.net.SocketTimeoutException;
31
+ import java.net.URL;
32
+ import java.net.URLConnection;
33
+ import java.util.HashMap;
34
+ import java.util.Map;
35
+ import java.util.UUID;
36
+
37
+ /**
38
+ * Helper class meant to be used with the android.webkit.WebView class to enable hosting assets,
39
+ * resources and other data on 'virtual' http(s):// URL.
40
+ * Hosting assets and resources on http(s):// URLs is desirable as it is compatible with the
41
+ * Same-Origin policy.
42
+ * <p>
43
+ * This class is intended to be used from within the
44
+ * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView, String)} and
45
+ * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView,
46
+ * android.webkit.WebResourceRequest)}
47
+ * methods.
48
+ */
49
+ public class WebViewLocalServer {
50
+ private static String TAG = "WebViewAssetServer";
51
+ private String basePath;
52
+ public final static String httpScheme = "http";
53
+ public final static String httpsScheme = "https";
54
+ public final static String fileStart = "/_app_file_";
55
+ public final static String contentStart = "/_app_content_";
56
+
57
+ private final UriMatcher uriMatcher;
58
+ private final AndroidProtocolHandler protocolHandler;
59
+ private final String authority;
60
+ private final String customScheme;
61
+ // Whether we're serving local files or proxying (for example, when doing livereload on a
62
+ // non-local endpoint (will be false in that case)
63
+ private boolean isAsset;
64
+ // Whether to route all requests to paths without extensions back to `index.html`
65
+ private final boolean html5mode;
66
+ private ConfigXmlParser parser;
67
+
68
+ public String getAuthority() { return authority; }
69
+
70
+ /**
71
+ * A handler that produces responses for paths on the virtual asset server.
72
+ * <p>
73
+ * Methods of this handler will be invoked on a background thread and care must be taken to
74
+ * correctly synchronize access to any shared state.
75
+ * <p>
76
+ * On Android KitKat and above these methods may be called on more than one thread. This thread
77
+ * may be different than the thread on which the shouldInterceptRequest method was invoke.
78
+ * This means that on Android KitKat and above it is possible to block in this method without
79
+ * blocking other resources from loading. The number of threads used to parallelize loading
80
+ * is an internal implementation detail of the WebView and may change between updates which
81
+ * means that the amount of time spend blocking in this method should be kept to an absolute
82
+ * minimum.
83
+ */
84
+ public abstract static class PathHandler {
85
+ protected String mimeType;
86
+ private String encoding;
87
+ private String charset;
88
+ private int statusCode;
89
+ private String reasonPhrase;
90
+ private Map<String, String> responseHeaders;
91
+
92
+ public PathHandler() {
93
+ this(null, null, 200, "OK", null);
94
+ }
95
+
96
+ public PathHandler(String encoding, String charset, int statusCode,
97
+ String reasonPhrase, Map<String, String> responseHeaders) {
98
+ this.encoding = encoding;
99
+ this.charset = charset;
100
+ this.statusCode = statusCode;
101
+ this.reasonPhrase = reasonPhrase;
102
+ Map<String, String> tempResponseHeaders;
103
+ if (responseHeaders == null) {
104
+ tempResponseHeaders = new HashMap<String, String>();
105
+ } else {
106
+ tempResponseHeaders = responseHeaders;
107
+ }
108
+ tempResponseHeaders.put("Cache-Control", "no-cache");
109
+ this.responseHeaders = tempResponseHeaders;
110
+ }
111
+
112
+ abstract public InputStream handle(Uri url);
113
+
114
+ public String getEncoding() {
115
+ return encoding;
116
+ }
117
+
118
+ public String getCharset() {
119
+ return charset;
120
+ }
121
+
122
+ public int getStatusCode() {
123
+ return statusCode;
124
+ }
125
+
126
+ public String getReasonPhrase() {
127
+ return reasonPhrase;
128
+ }
129
+
130
+ public Map<String, String> getResponseHeaders() {
131
+ return responseHeaders;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Information about the URLs used to host the assets in the WebView.
137
+ */
138
+ public static class AssetHostingDetails {
139
+ private Uri httpPrefix;
140
+ private Uri httpsPrefix;
141
+
142
+ /*package*/ AssetHostingDetails(Uri httpPrefix, Uri httpsPrefix) {
143
+ this.httpPrefix = httpPrefix;
144
+ this.httpsPrefix = httpsPrefix;
145
+ }
146
+
147
+ /**
148
+ * Gets the http: scheme prefix at which assets are hosted.
149
+ *
150
+ * @return the http: scheme prefix at which assets are hosted. Can return null.
151
+ */
152
+ public Uri getHttpPrefix() {
153
+ return httpPrefix;
154
+ }
155
+
156
+ /**
157
+ * Gets the https: scheme prefix at which assets are hosted.
158
+ *
159
+ * @return the https: scheme prefix at which assets are hosted. Can return null.
160
+ */
161
+ public Uri getHttpsPrefix() {
162
+ return httpsPrefix;
163
+ }
164
+ }
165
+
166
+ WebViewLocalServer(Context context, String authority, boolean html5mode, ConfigXmlParser parser, String customScheme) {
167
+ uriMatcher = new UriMatcher(null);
168
+ this.html5mode = html5mode;
169
+ this.parser = parser;
170
+ this.protocolHandler = new AndroidProtocolHandler(context.getApplicationContext());
171
+ this.authority = authority;
172
+ this.customScheme = customScheme;
173
+ }
174
+
175
+ private static Uri parseAndVerifyUrl(String url) {
176
+ if (url == null) {
177
+ return null;
178
+ }
179
+ Uri uri = Uri.parse(url);
180
+ if (uri == null) {
181
+ Log.e(TAG, "Malformed URL: " + url);
182
+ return null;
183
+ }
184
+ String path = uri.getPath();
185
+ if (path == null || path.length() == 0) {
186
+ Log.e(TAG, "URL does not have a path: " + url);
187
+ return null;
188
+ }
189
+ return uri;
190
+ }
191
+
192
+ private static WebResourceResponse createWebResourceResponse(String mimeType, String encoding, int statusCode, String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
193
+ if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
194
+ int finalStatusCode = statusCode;
195
+ try {
196
+ if (data.available() == 0) {
197
+ finalStatusCode = 404;
198
+ }
199
+ } catch (IOException e) {
200
+ finalStatusCode = 500;
201
+ }
202
+ return new WebResourceResponse(mimeType, encoding, finalStatusCode, reasonPhrase, responseHeaders, data);
203
+ } else {
204
+ return new WebResourceResponse(mimeType, encoding, data);
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Attempt to retrieve the WebResourceResponse associated with the given <code>request</code>.
210
+ * This method should be invoked from within
211
+ * {@link android.webkit.WebViewClient#shouldInterceptRequest(android.webkit.WebView,
212
+ * android.webkit.WebResourceRequest)}.
213
+ *
214
+ * @param uri the request Uri to process.
215
+ * @return a response if the request URL had a matching handler, null if no handler was found.
216
+ */
217
+ public WebResourceResponse shouldInterceptRequest(Uri uri, WebResourceRequest request) {
218
+ PathHandler handler;
219
+ synchronized (uriMatcher) {
220
+ handler = (PathHandler) uriMatcher.match(uri);
221
+ }
222
+ if (handler == null) {
223
+ return null;
224
+ }
225
+
226
+ if (isLocalFile(uri) || uri.getAuthority().equals(this.authority)) {
227
+ Log.d("SERVER", "Handling local request: " + uri.toString());
228
+ return handleLocalRequest(uri, handler, request);
229
+ } else {
230
+ return handleProxyRequest(uri, handler);
231
+ }
232
+ }
233
+
234
+ private boolean isLocalFile(Uri uri) {
235
+ String path = uri.getPath();
236
+ if (path.startsWith(contentStart) || path.startsWith(fileStart)) {
237
+ return true;
238
+ }
239
+ return false;
240
+ }
241
+
242
+
243
+ private WebResourceResponse handleLocalRequest(Uri uri, PathHandler handler, WebResourceRequest request) {
244
+ String path = uri.getPath();
245
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && request != null && request.getRequestHeaders().get("Range") != null) {
246
+ InputStream responseStream = new LollipopLazyInputStream(handler, uri);
247
+ String mimeType = getMimeType(path, responseStream);
248
+ Map<String, String> tempResponseHeaders = handler.getResponseHeaders();
249
+ int statusCode = 206;
250
+ try {
251
+ int totalRange = responseStream.available();
252
+ String rangeString = request.getRequestHeaders().get("Range");
253
+ String[] parts = rangeString.split("=");
254
+ String[] streamParts = parts[1].split("-");
255
+ String fromRange = streamParts[0];
256
+ int range = totalRange-1;
257
+ if (streamParts.length > 1) {
258
+ range = Integer.parseInt(streamParts[1]);
259
+ }
260
+ tempResponseHeaders.put("Accept-Ranges", "bytes");
261
+ tempResponseHeaders.put("Content-Range", "bytes " + fromRange + "-" + range + "/" + totalRange);
262
+ } catch (IOException e) {
263
+ statusCode = 404;
264
+ }
265
+ return createWebResourceResponse(mimeType, handler.getEncoding(),
266
+ statusCode, handler.getReasonPhrase(), tempResponseHeaders, responseStream);
267
+ }
268
+ if (isLocalFile(uri)) {
269
+ InputStream responseStream = new LollipopLazyInputStream(handler, uri);
270
+ String mimeType = getMimeType(path, responseStream);
271
+ return createWebResourceResponse(mimeType, handler.getEncoding(),
272
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), responseStream);
273
+ }
274
+
275
+ if (path.equals("") || path.equals("/") || (!uri.getLastPathSegment().contains(".") && html5mode)) {
276
+ InputStream stream;
277
+ String launchURL = parser.getLaunchUrl();
278
+ String launchFile = launchURL.substring(launchURL.lastIndexOf("/") + 1, launchURL.length());
279
+ try {
280
+ String startPath = this.basePath + "/" + launchFile;
281
+ if (isAsset) {
282
+ stream = protocolHandler.openAsset(startPath);
283
+ } else {
284
+ stream = protocolHandler.openFile(startPath);
285
+ }
286
+
287
+ } catch (IOException e) {
288
+ Log.e(TAG, "Unable to open " + launchFile, e);
289
+ return null;
290
+ }
291
+
292
+ return createWebResourceResponse("text/html", handler.getEncoding(),
293
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), stream);
294
+ }
295
+
296
+ int periodIndex = path.lastIndexOf(".");
297
+ if (periodIndex >= 0) {
298
+ InputStream responseStream = new LollipopLazyInputStream(handler, uri);
299
+ String mimeType = getMimeType(path, responseStream);
300
+ return createWebResourceResponse(mimeType, handler.getEncoding(),
301
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), responseStream);
302
+ }
303
+
304
+ return null;
305
+ }
306
+
307
+ /**
308
+ * Instead of reading files from the filesystem/assets, proxy through to the URL
309
+ * and let an external server handle it.
310
+ * @param uri
311
+ * @param handler
312
+ * @return
313
+ */
314
+ private WebResourceResponse handleProxyRequest(Uri uri, PathHandler handler) {
315
+ try {
316
+ String path = uri.getPath();
317
+ URL url = new URL(uri.toString());
318
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
319
+ conn.setRequestMethod("GET");
320
+ conn.setReadTimeout(30 * 1000);
321
+ conn.setConnectTimeout(30 * 1000);
322
+
323
+ InputStream stream = conn.getInputStream();
324
+
325
+ if (path.equals("/") || (!uri.getLastPathSegment().contains(".") && html5mode)) {
326
+ return createWebResourceResponse("text/html", handler.getEncoding(),
327
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), stream);
328
+ }
329
+
330
+ int periodIndex = path.lastIndexOf(".");
331
+ if (periodIndex >= 0) {
332
+ String ext = path.substring(path.lastIndexOf("."), path.length());
333
+
334
+ // TODO: Conjure up a bit more subtlety than this
335
+ if (ext.equals(".html")) {
336
+ }
337
+
338
+ String mimeType = getMimeType(path, stream);
339
+
340
+ return createWebResourceResponse(mimeType, handler.getEncoding(),
341
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), stream);
342
+ }
343
+
344
+ return createWebResourceResponse("", handler.getEncoding(),
345
+ handler.getStatusCode(), handler.getReasonPhrase(), handler.getResponseHeaders(), stream);
346
+
347
+ } catch (SocketTimeoutException ex) {
348
+ // bridge.handleAppUrlLoadError(ex);
349
+ } catch (Exception ex) {
350
+ // bridge.handleAppUrlLoadError(ex);
351
+ }
352
+ return null;
353
+ }
354
+
355
+ private String getMimeType(String path, InputStream stream) {
356
+ String mimeType = null;
357
+ try {
358
+ mimeType = URLConnection.guessContentTypeFromName(path); // Does not recognize *.js
359
+ if (mimeType != null && path.endsWith(".js") && mimeType.equals("image/x-icon")) {
360
+ Log.d(IonicWebViewEngine.TAG, "We shouldn't be here");
361
+ }
362
+ if (mimeType == null) {
363
+ if (path.endsWith(".js") || path.endsWith(".mjs")) {
364
+ // Make sure JS files get the proper mimetype to support ES modules
365
+ mimeType = "application/javascript";
366
+ } else if (path.endsWith(".wasm")) {
367
+ mimeType = "application/wasm";
368
+ } else {
369
+ mimeType = URLConnection.guessContentTypeFromStream(stream);
370
+ }
371
+ }
372
+ } catch (Exception ex) {
373
+ Log.e(TAG, "Unable to get mime type" + path, ex);
374
+ }
375
+ return mimeType;
376
+ }
377
+
378
+ /**
379
+ * Registers a handler for the given <code>uri</code>. The <code>handler</code> will be invoked
380
+ * every time the <code>shouldInterceptRequest</code> method of the instance is called with
381
+ * a matching <code>uri</code>.
382
+ *
383
+ * @param uri the uri to use the handler for. The scheme and authority (domain) will be matched
384
+ * exactly. The path may contain a '*' element which will match a single element of
385
+ * a path (so a handler registered for /a/* will be invoked for /a/b and /a/c.html
386
+ * but not for /a/b/b) or the '**' element which will match any number of path
387
+ * elements.
388
+ * @param handler the handler to use for the uri.
389
+ */
390
+ void register(Uri uri, PathHandler handler) {
391
+ synchronized (uriMatcher) {
392
+ uriMatcher.addURI(uri.getScheme(), uri.getAuthority(), uri.getPath(), handler);
393
+ }
394
+ }
395
+
396
+ /**
397
+ * Hosts the application's assets on an http(s):// URL. Assets from the local path
398
+ * <code>assetPath/...</code> will be available under
399
+ * <code>http(s)://{uuid}.androidplatform.net/assets/...</code>.
400
+ *
401
+ * @param assetPath the local path in the application's asset folder which will be made
402
+ * available by the server (for example "/www").
403
+ */
404
+ public void hostAssets(String assetPath) {
405
+ hostAssets(authority, assetPath);
406
+ }
407
+
408
+
409
+ /**
410
+ * Hosts the application's assets on an http(s):// URL. Assets from the local path
411
+ * <code>assetPath/...</code> will be available under
412
+ * <code>http(s)://{domain}/{virtualAssetPath}/...</code>.
413
+ *
414
+ * @param domain custom domain on which the assets should be hosted (for example "example.com").
415
+ * @param assetPath the local path in the application's asset folder which will be made
416
+ * available by the server (for example "/www").
417
+ * @return prefixes under which the assets are hosted.
418
+ */
419
+ public void hostAssets(final String domain,
420
+ final String assetPath) {
421
+ this.isAsset = true;
422
+ this.basePath = assetPath;
423
+
424
+ createHostingDetails();
425
+ }
426
+
427
+ private void createHostingDetails() {
428
+ final String assetPath = this.basePath;
429
+
430
+ if (assetPath.indexOf('*') != -1) {
431
+ throw new IllegalArgumentException("assetPath cannot contain the '*' character.");
432
+ }
433
+
434
+ PathHandler handler = new PathHandler() {
435
+ @Override
436
+ public InputStream handle(Uri url) {
437
+ InputStream stream = null;
438
+ String path = url.getPath();
439
+ try {
440
+ if (path.startsWith(contentStart)) {
441
+ stream = protocolHandler.openContentUrl(url);
442
+ } else if (path.startsWith(fileStart) || !isAsset) {
443
+ if (!path.startsWith(fileStart)) {
444
+ path = basePath + url.getPath();
445
+ }
446
+ stream = protocolHandler.openFile(path);
447
+ } else {
448
+ stream = protocolHandler.openAsset(assetPath + path);
449
+ }
450
+ } catch (IOException e) {
451
+ Log.e(TAG, "Unable to open asset URL: " + url);
452
+ return null;
453
+ }
454
+
455
+ return stream;
456
+ }
457
+ };
458
+
459
+ registerUriForScheme(httpScheme, handler, authority);
460
+ registerUriForScheme(httpsScheme, handler, authority);
461
+ if (!customScheme.equals(httpScheme) && !customScheme.equals(httpsScheme)) {
462
+ registerUriForScheme(customScheme, handler, authority);
463
+ }
464
+
465
+ }
466
+
467
+ private void registerUriForScheme(String scheme, PathHandler handler, String authority) {
468
+ Uri.Builder uriBuilder = new Uri.Builder();
469
+ uriBuilder.scheme(scheme);
470
+ uriBuilder.authority(authority);
471
+ uriBuilder.path("");
472
+ Uri uriPrefix = uriBuilder.build();
473
+
474
+ register(Uri.withAppendedPath(uriPrefix, "/"), handler);
475
+ register(Uri.withAppendedPath(uriPrefix, "**"), handler);
476
+ }
477
+
478
+ /**
479
+ * Hosts the application's resources on an http(s):// URL. Resources
480
+ * <code>http(s)://{uuid}.androidplatform.net/res/{resource_type}/{resource_name}</code>.
481
+ *
482
+ * @return prefixes under which the resources are hosted.
483
+ */
484
+ public AssetHostingDetails hostResources() {
485
+ return hostResources(authority, "/res", true, true);
486
+ }
487
+
488
+ /**
489
+ * Hosts the application's resources on an http(s):// URL. Resources
490
+ * <code>http(s)://{uuid}.androidplatform.net/{virtualResourcesPath}/{resource_type}/{resource_name}</code>.
491
+ *
492
+ * @param virtualResourcesPath the path on the local server under which the resources
493
+ * should be hosted.
494
+ * @param enableHttp whether to enable hosting using the http scheme.
495
+ * @param enableHttps whether to enable hosting using the https scheme.
496
+ * @return prefixes under which the resources are hosted.
497
+ */
498
+ public AssetHostingDetails hostResources(final String virtualResourcesPath, boolean enableHttp,
499
+ boolean enableHttps) {
500
+ return hostResources(authority, virtualResourcesPath, enableHttp, enableHttps);
501
+ }
502
+
503
+ /**
504
+ * Hosts the application's resources on an http(s):// URL. Resources
505
+ * <code>http(s)://{domain}/{virtualResourcesPath}/{resource_type}/{resource_name}</code>.
506
+ *
507
+ * @param domain custom domain on which the assets should be hosted (for example "example.com").
508
+ * If untrusted content is to be loaded into the WebView it is advised to make
509
+ * this random.
510
+ * @param virtualResourcesPath the path on the local server under which the resources
511
+ * should be hosted.
512
+ * @param enableHttp whether to enable hosting using the http scheme.
513
+ * @param enableHttps whether to enable hosting using the https scheme.
514
+ * @return prefixes under which the resources are hosted.
515
+ */
516
+ public AssetHostingDetails hostResources(final String domain,
517
+ final String virtualResourcesPath, boolean enableHttp,
518
+ boolean enableHttps) {
519
+ if (virtualResourcesPath.indexOf('*') != -1) {
520
+ throw new IllegalArgumentException(
521
+ "virtualResourcesPath cannot contain the '*' character.");
522
+ }
523
+
524
+ Uri.Builder uriBuilder = new Uri.Builder();
525
+ uriBuilder.scheme(httpScheme);
526
+ uriBuilder.authority(domain);
527
+ uriBuilder.path(virtualResourcesPath);
528
+
529
+ Uri httpPrefix = null;
530
+ Uri httpsPrefix = null;
531
+
532
+ PathHandler handler = new PathHandler() {
533
+ @Override
534
+ public InputStream handle(Uri url) {
535
+ InputStream stream = protocolHandler.openResource(url);
536
+ String mimeType = null;
537
+ try {
538
+ mimeType = URLConnection.guessContentTypeFromStream(stream);
539
+ } catch (Exception ex) {
540
+ Log.e(TAG, "Unable to get mime type" + url);
541
+ }
542
+
543
+ return stream;
544
+ }
545
+ };
546
+
547
+ if (enableHttp) {
548
+ httpPrefix = uriBuilder.build();
549
+ register(Uri.withAppendedPath(httpPrefix, "**"), handler);
550
+ }
551
+ if (enableHttps) {
552
+ uriBuilder.scheme(httpsScheme);
553
+ httpsPrefix = uriBuilder.build();
554
+ register(Uri.withAppendedPath(httpsPrefix, "**"), handler);
555
+ }
556
+ return new AssetHostingDetails(httpPrefix, httpsPrefix);
557
+ }
558
+
559
+
560
+ /**
561
+ * Hosts the application's files on an http(s):// URL. Files from the basePath
562
+ * <code>basePath/...</code> will be available under
563
+ * <code>http(s)://{uuid}.androidplatform.net/...</code>.
564
+ *
565
+ * @param basePath the local path in the application's data folder which will be made
566
+ * available by the server (for example "/www").
567
+ */
568
+ public void hostFiles(final String basePath) {
569
+ this.isAsset = false;
570
+ this.basePath = basePath;
571
+ createHostingDetails();
572
+ }
573
+
574
+ /**
575
+ * The KitKat WebView reads the InputStream on a separate threadpool. We can use that to
576
+ * parallelize loading.
577
+ */
578
+ private static abstract class LazyInputStream extends InputStream {
579
+ protected final PathHandler handler;
580
+ private InputStream is = null;
581
+
582
+ public LazyInputStream(PathHandler handler) {
583
+ this.handler = handler;
584
+ }
585
+
586
+ private InputStream getInputStream() {
587
+ if (is == null) {
588
+ is = handle();
589
+ }
590
+ return is;
591
+ }
592
+
593
+ protected abstract InputStream handle();
594
+
595
+ @Override
596
+ public int available() throws IOException {
597
+ InputStream is = getInputStream();
598
+ return (is != null) ? is.available() : 0;
599
+ }
600
+
601
+ @Override
602
+ public int read() throws IOException {
603
+ InputStream is = getInputStream();
604
+ return (is != null) ? is.read() : -1;
605
+ }
606
+
607
+ @Override
608
+ public int read(byte b[]) throws IOException {
609
+ InputStream is = getInputStream();
610
+ return (is != null) ? is.read(b) : -1;
611
+ }
612
+
613
+ @Override
614
+ public int read(byte b[], int off, int len) throws IOException {
615
+ InputStream is = getInputStream();
616
+ return (is != null) ? is.read(b, off, len) : -1;
617
+ }
618
+
619
+ @Override
620
+ public long skip(long n) throws IOException {
621
+ InputStream is = getInputStream();
622
+ return (is != null) ? is.skip(n) : 0;
623
+ }
624
+ }
625
+
626
+ // For L and above.
627
+ private static class LollipopLazyInputStream extends LazyInputStream {
628
+ private Uri uri;
629
+ private InputStream is;
630
+
631
+ public LollipopLazyInputStream(PathHandler handler, Uri uri) {
632
+ super(handler);
633
+ this.uri = uri;
634
+ }
635
+
636
+ @Override
637
+ protected InputStream handle() {
638
+ return handler.handle(uri);
639
+ }
640
+ }
641
+
642
+ public String getBasePath(){
643
+ return this.basePath;
644
+ }
645
+ }
@@ -0,0 +1,27 @@
1
+ /*
2
+ Licensed to the Apache Software Foundation (ASF) under one
3
+ or more contributor license agreements. See the NOTICE file
4
+ distributed with this work for additional information
5
+ regarding copyright ownership. The ASF licenses this file
6
+ to you under the Apache License, Version 2.0 (the
7
+ "License"); you may not use this file except in compliance
8
+ with the License. You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing,
13
+ software distributed under the License is distributed on an
14
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ KIND, either express or implied. See the License for the
16
+ specific language governing permissions and limitations
17
+ under the License.
18
+ */
19
+
20
+ #import <WebKit/WebKit.h>
21
+
22
+ @interface CDVWKProcessPoolFactory : NSObject
23
+ @property (nonatomic, retain) WKProcessPool* sharedPool;
24
+
25
+ +(instancetype) sharedFactory;
26
+ -(WKProcessPool*) sharedProcessPool;
27
+ @end