├── .eslintrc.js ├── .gitattributes ├── .github ├── FUNDING.yml ├── issue_template.md └── workflows │ └── release.yml ├── .gitignore ├── .gitmodules ├── .npmrc ├── .prettierignore ├── .prettierrc ├── .prettierrc.js ├── .yarnrc.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── config.json ├── demo-snippets ├── assets │ ├── test-data │ │ ├── css │ │ │ └── local-stylesheet.css │ │ ├── html │ │ │ ├── camera.html │ │ │ ├── css-not-predefined.html │ │ │ ├── css-predefined-link-tags.html │ │ │ ├── empty.html │ │ │ ├── javascript-calls-x-local.html │ │ │ └── javascript-calls.html │ │ └── js │ │ │ └── local-javascript.js │ └── www │ │ └── index.html ├── ng │ ├── basic-example │ │ ├── basic-example.component.html │ │ ├── basic-example.component.scss │ │ └── basic-example.component.ts │ └── install.module.ts ├── package.json ├── react │ ├── BasicExample.tsx │ └── install.ts ├── svelte │ ├── BasicExample.svelte │ └── install.ts └── vue │ ├── BasicExample.vue │ └── install.ts ├── detox.config.js ├── devices.js ├── docs ├── .nojekyll ├── assets │ ├── hierarchy.js │ ├── highlight.css │ ├── icons.js │ ├── icons.svg │ ├── main.js │ ├── navigation.js │ ├── search.js │ └── style.css ├── classes │ ├── webview.AWebView.html │ ├── webview.UnsupportedSDKError.html │ └── webview.WebViewExtBase.html ├── enums │ └── webview.EventNames.html ├── functions │ └── webview-rtc.default.html ├── hierarchy.html ├── index.html ├── interfaces │ ├── webview.EnterFullscreenEventData.html │ ├── webview.ExitFullscreenEventData.html │ ├── webview.InjectExecuteJavaScript.html │ ├── webview.LoadEventData.html │ ├── webview.LoadFinishedEventData.html │ ├── webview.LoadJavaScriptResource.html │ ├── webview.LoadProgressEventData.html │ ├── webview.LoadStartedEventData.html │ ├── webview.LoadStyleSheetResource.html │ ├── webview.RequestPermissionsEventData.html │ ├── webview.ShouldOverideUrlLoadEventData.html │ ├── webview.ShouldOverrideUrlLoadEventData.html │ ├── webview.TitleChangedEventData.html │ ├── webview.ViewPortProperties.html │ ├── webview.WebAlertEventData.html │ ├── webview.WebConfirmEventData.html │ ├── webview.WebConsoleEventData.html │ ├── webview.WebPromptEventData.html │ ├── webview.WebViewEventData.html │ └── webview.WebViewExtEventData.html ├── modules.html ├── modules │ ├── webview-rtc.html │ └── webview.html ├── types │ ├── webview.CacheMode.html │ ├── webview.NavigationType.html │ └── webview.ViewPortValue.html └── variables │ ├── webview.WebViewTraceCategory.html │ ├── webview.allowsInlineMediaPlaybackProperty.html │ ├── webview.autoInjectJSBridgeProperty.html │ ├── webview.builtInZoomControlsProperty.html │ ├── webview.cacheModeProperty.html │ ├── webview.customUserAgentProperty.html │ ├── webview.databaseStorageProperty.html │ ├── webview.debugModeProperty.html │ ├── webview.displayZoomControlsProperty.html │ ├── webview.domStorageProperty.html │ ├── webview.isScrollEnabledProperty.html │ ├── webview.limitsNavigationsToAppBoundDomainsProperty.html │ ├── webview.mediaPlaybackRequiresUserActionProperty.html │ ├── webview.scalesPageToFitProperty.html │ ├── webview.scrollBarIndicatorVisibleProperty.html │ ├── webview.scrollBounceProperty.html │ ├── webview.srcProperty.html │ ├── webview.supportZoomProperty.html │ ├── webview.useWideViewPortProperty.html │ ├── webview.viewPortProperty.html │ └── webview.webConsoleProperty.html ├── e2e ├── config.json ├── environment.js ├── run-tests.js └── tests.e2e.js ├── images ├── demo-android.gif └── demo-ios.gif ├── lerna.json ├── make-bridge-loader.ts ├── package.json ├── packages ├── webview-rtc │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── platforms │ │ └── ios │ │ │ └── Podfile │ └── tsconfig.json └── webview │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── platforms │ ├── android │ │ ├── AndroidManifest.xml │ │ ├── buildscript.gradle │ │ ├── include.gradle │ │ ├── java │ │ │ └── com │ │ │ │ └── nativescript │ │ │ │ └── webviewinterface │ │ │ │ ├── WebChromeClient.java │ │ │ │ ├── WebView.java │ │ │ │ └── WebViewBridgeInterface.java │ │ └── native-api-usage.json │ └── ios │ │ ├── native-api-usage.json │ │ └── src │ │ ├── Constants.swift │ │ ├── Info.plist │ │ ├── WKWebviewCustomSchemeHandler.swift │ │ └── module.modulemap │ └── tsconfig.json ├── pnpm-workspace.yaml ├── references.d.ts ├── src-native └── webview │ └── android │ ├── .gitignore │ ├── .project │ ├── .settings │ └── org.eclipse.buildship.core.prefs │ ├── app │ ├── .classpath │ ├── .gitignore │ ├── .project │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── androidTest │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── triniwiz │ │ │ └── imagedemo │ │ │ └── ExampleInstrumentedTest.kt │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── nativescript │ │ │ │ └── imagedemo │ │ │ │ ├── Data.kt │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable-v24 │ │ │ └── ic_launcher_foreground.xml │ │ │ ├── drawable │ │ │ ├── bg.xml │ │ │ ├── error.png │ │ │ ├── ic_launcher_background.xml │ │ │ └── law.jpg │ │ │ ├── layout │ │ │ ├── activity_main.xml │ │ │ └── list_item.xml │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ │ └── values │ │ │ ├── attrs.xml │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── triniwiz │ │ └── imagedemo │ │ └── ExampleUnitTest.kt │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle │ └── webview │ ├── .gitignore │ ├── build.gradle │ ├── consumer-rules.pro │ ├── proguard-rules.pro │ └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── nativescript │ │ └── image │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ └── res │ │ ├── drawable-hdpi │ │ └── ic_indicator.png │ │ ├── drawable-mdpi │ │ └── ic_indicator.png │ │ ├── drawable-xhdpi │ │ └── ic_indicator.png │ │ ├── drawable-xxhdpi │ │ └── ic_indicator.png │ │ ├── drawable-xxxhdpi │ │ └── ic_indicator.png │ │ ├── drawable │ │ └── progress_animation.xml │ │ └── values │ │ └── attrs.xml │ └── test │ └── java │ └── com │ └── nativescript │ └── image │ └── ExampleUnitTest.java ├── src ├── webview-rtc │ ├── index.android.ts │ ├── index.common.ts │ ├── index.d.ts │ ├── index.ios.ts │ └── types │ │ └── ios │ │ └── objc!WKWebViewRTC.d.ts └── webview │ ├── angular │ ├── index.ts │ ├── ng-package.json │ ├── package.json │ └── tsconfig.json │ ├── index.android.ts │ ├── index.common.ts │ ├── index.d.ts │ ├── index.ios.ts │ ├── nativescript-webview-bridge-loader.android.ts │ ├── nativescript-webview-bridge-loader.d.ts │ ├── nativescript-webview-bridge-loader.ios.ts │ ├── references.d.ts │ ├── types │ ├── android │ │ └── webviewinterface.d.ts │ ├── ios │ │ └── ios.d.ts │ └── url.d.ts │ └── vue │ └── index.ts ├── svelte.config.js ├── tsconfig.eslint.json ├── tsconfig.json ├── tsconfig.vue3.json ├── www-src ├── bridge-loader.android.ts.tmpl ├── bridge-loader.ios.ts.tmpl ├── bridge.android.ts ├── bridge.common.ts ├── bridge.ios.ts ├── metadata-view-port.ts ├── package.json ├── rollup.config.mjs ├── tsconfig.json └── yarn.lock └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: './tools/.eslintrc.js' 3 | }; 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [farfromrefug] 2 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Make sure to check the demo app(s) for sample usage 2 | 3 | ### Make sure to check the existing issues in this repository 4 | 5 | ### If the demo apps cannot help and there is no issue for your problem, tell us about it 6 | Please, ensure your title is less than 63 characters long and starts with a capital 7 | letter. 8 | 9 | ### Which platform(s) does your issue occur on? 10 | - iOS/Android/Both 11 | - iOS/Android versions 12 | - emulator or device. What type of device? 13 | 14 | ### Please, provide the following version numbers that your issue occurs with: 15 | 16 | - CLI: (run `tns --version` to fetch it) 17 | - Cross-platform modules: (check the 'version' attribute in the 18 | `node_modules/@nativescript/core/package.json` file in your project) 19 | - Runtime(s): (look for the `"tns-android"` and `"tns-ios"` properties in the `package.json` file of your project) 20 | - Plugin(s): (look for the version numbers in the `package.json` file of your 21 | project and paste your dependencies and devDependencies here) 22 | 23 | ### Please, tell us how to recreate the issue in as much detail as possible. 24 | Describe the steps to reproduce it. 25 | 26 | ### Is there any code involved? 27 | - provide a code example to recreate the problem 28 | - (EVEN BETTER) provide a .zip with application or refer to a repository with application where the problem is reproducible. 29 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: 'release' 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | type: choice 8 | default: auto 9 | description: What kind of version upgrade 10 | options: 11 | - auto 12 | - patch 13 | - minor 14 | - major 15 | 16 | jobs: 17 | release: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repository 21 | uses: actions/checkout@v4 22 | with: 23 | fetch-depth: "0" 24 | submodules: true 25 | 26 | - name: setup node 27 | uses: actions/setup-node@v4 28 | with: 29 | node-version: lts/* 30 | registry-url: 'https://registry.npmjs.org' 31 | 32 | 33 | - uses: oNaiPs/secrets-to-env-action@v1 34 | with: 35 | secrets: ${{ toJSON(secrets) }} 36 | 37 | 38 | - uses: oleksiyrudenko/gha-git-credentials@v2-latest 39 | with: 40 | token: '${{ secrets.GITHUB_TOKEN }}' 41 | name: Martin Guillon 42 | email: dev@akylas.fr 43 | 44 | - name: install jq 45 | run: sudo apt install jq 46 | 47 | - name: Enable CorePack 48 | run: | 49 | corepack enable 50 | yarn config get globalFolder # the yarn command will ensure the correct yarn version is downloaded and installed 51 | 52 | - name: Get yarn cache directory path 53 | id: yarn-cache-dir-path 54 | run: echo "::set-output name=dir::$(yarn config get globalFolder)" 55 | 56 | - name: Remove package.json resolutions 57 | run: echo "`jq 'delpaths([["resolutions"]])' package.json`" > package.json 58 | 59 | - uses: actions/cache@v4 60 | name: Handle node_modules Cache 61 | id: yarn-node_modules # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 62 | with: 63 | path: node_modules 64 | key: ${{ runner.os }}-yarn-node_modules-${{ hashFiles('**/yarn.lock') }} 65 | restore-keys: | 66 | ${{ runner.os }}-node_modules- 67 | 68 | - uses: actions/cache@v4 69 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 70 | name: Handle Yarn cache 71 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 72 | with: 73 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 74 | key: ${{ runner.os }}-yarn-cache-${{ hashFiles('**/yarn.lock') }} 75 | restore-keys: | 76 | ${{ runner.os }}-yarn- 77 | 78 | - name: Install deps 79 | if: steps.yarn-node_modules.outputs.cache-hit != 'true' 80 | uses: bahmutov/npm-install@v1 81 | with: 82 | install-command: yarn install --silent 83 | env: 84 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 85 | 86 | - name: run setup 87 | run: | 88 | npm run setup 89 | 90 | - name: "NPM Identity" 91 | env: 92 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 93 | run: | 94 | echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc 95 | 96 | - name: publish auto 97 | if: github.event.inputs.release_type == 'auto' 98 | run: | 99 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes 100 | env: 101 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 102 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 103 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 104 | 105 | - name: publish 106 | if: github.event.inputs.release_type != 'auto' 107 | run: | 108 | npm run publish -- --force-publish --no-verify-access --no-private --no-commit-hooks --yes --bump ${{ github.event.inputs.release_type }} 109 | env: 110 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 111 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 112 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # NativeScript 2 | hooks/ 3 | node_modules/ 4 | platforms 5 | 6 | # NativeScript Template 7 | *.js.map 8 | !ngcc.config.js 9 | !webpack.config.js 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # General 19 | .DS_Store 20 | .AppleDouble 21 | .LSOverride 22 | .idea 23 | .cloud 24 | .gradle 25 | .project 26 | .yarn 27 | .cxx 28 | tmp/ 29 | 30 | !.eslintrc.js 31 | !.prettierrc.js 32 | 33 | !e2e/*.js 34 | !detox.config.js 35 | devices.js 36 | 37 | *.framework 38 | *.xcframework 39 | **/*.js.map 40 | src/**/*.js 41 | packages/**/*.js 42 | packages/**/*.d.ts 43 | bin 44 | build 45 | Pods 46 | !packages/*/platforms 47 | /packages/**/*.aar 48 | /packages/**/*.framework 49 | /packages/**/*.xcframework 50 | /demo-snippets/**/*.aar 51 | *.xcuserdatad 52 | /packages/README.md 53 | packages/**/*js.map 54 | packages/**/*js 55 | packages/angular 56 | packages/typings 57 | packages/**/angular/*.json 58 | packages/**/*.ngsummary.json 59 | packages/**/*.metadata.json 60 | 61 | .vscode/settings.json 62 | 63 | /blueprint.md -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "tools"] 2 | path = tools 3 | url = https://github.com/nativescript-community/plugin-seed-tools.git 4 | [submodule "demo-vue"] 5 | path = demo-vue 6 | url = https://github.com/nativescript-community/plugin-seed-demo-vue.git 7 | [submodule "demo-react"] 8 | path = demo-react 9 | url = https://github.com/nativescript-community/plugin-seed-demo-react.git 10 | [submodule "demo-svelte"] 11 | path = demo-svelte 12 | url = https://github.com/nativescript-community/plugin-seed-demo-svelte.git 13 | [submodule "demo-ng"] 14 | path = demo-ng 15 | url = https://github.com/nativescript-community/plugin-seed-demo-ng.git 16 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | public-hoist-pattern[]=*eslint* 3 | public-hoist-pattern[]=source-map-support 4 | public-hoist-pattern[]=ts-patch 5 | public-hoist-pattern[]=typescript 6 | public-hoist-pattern[]=cpy-cli 7 | strict-peer-dependencies=false 8 | shell-emulator=true 9 | auto-install-peers=false 10 | loglevel=error 11 | engine-strict=true 12 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules/ 3 | plugin/ 4 | docs/ 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 200, 3 | "semi": true, 4 | "tabWidth": 4, 5 | "singleQuote": true, 6 | "trailingComma": "none" 7 | } -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 200, 3 | semi: true, 4 | tabWidth: 4, 5 | trailingComma: 'none', 6 | singleQuote: true 7 | }; 8 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | nmHoistingLimits: workspaces 4 | 5 | nodeLinker: node-modules 6 | 7 | yarnPath: tools/.yarn/releases/yarn-4.0.1.cjs 8 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "readme": true, 3 | "angular": true, 4 | "demos": [ 5 | "ng", 6 | "react", 7 | "svelte", 8 | "vue" 9 | ] 10 | } -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/css/local-stylesheet.css: -------------------------------------------------------------------------------- 1 | .red { 2 | margin: 0; 3 | padding: 0; 4 | font-weight: bolder; 5 | background-color: blue; 6 | color: green; 7 | font-size: 20pt; 8 | } 9 | 10 | body, 11 | html { 12 | margin: 0; 13 | padding: 0; 14 | background-color: purple; 15 | } 16 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/camera.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | Blank 22 | 23 | 24 | 26 | 27 | 28 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/css-not-predefined.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Inject stylesheet via x-local 5 | 6 | 7 |

RED

8 | 9 | 10 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/css-predefined-link-tags.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Load predefined x-local stylesheet 5 | 6 | 7 | 8 |

RED

9 | 10 | 11 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/empty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Blank 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/javascript-calls-x-local.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/html/javascript-calls.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 35 | 36 | 37 |

RED

38 |
39 |

Should overide url?

40 | Go to google - should not load 41 |
42 | 43 | 44 | -------------------------------------------------------------------------------- /demo-snippets/assets/test-data/js/local-javascript.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | function getNumber() { 4 | return 42; 5 | } 6 | 7 | function getNumberFloat() { 8 | return 3.14; 9 | } 10 | 11 | function getFalse() { 12 | return false; 13 | } 14 | 15 | function getTruth() { 16 | return true; 17 | } 18 | 19 | function getString() { 20 | return 'string result from webview JS function'; 21 | } 22 | 23 | function getArray() { 24 | return [1.5, true, 'hello']; 25 | } 26 | 27 | function getObject() { 28 | return { 29 | prop: 'test', 30 | name: 'object-test', 31 | values: [42, 3.14] 32 | }; 33 | } 34 | 35 | function setupEventListener() { 36 | window.nsWebViewBridge.on('tns-message', function (args) { 37 | window.nsWebViewBridge.emit('web-message', args); 38 | }); 39 | } 40 | 41 | function testPromiseResolve() { 42 | return new Promise(function (resolve) { 43 | setTimeout(function () { 44 | resolve(42); 45 | }, 100); 46 | }); 47 | } 48 | 49 | function testPromiseReject() { 50 | return new Promise(function (resolve, reject) { 51 | setTimeout(function () { 52 | reject(new Error('The Cake is a Lie')); 53 | }, 100); 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /demo-snippets/assets/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 47 | 48 | 49 |

RED

50 |
51 |

Should overide url?

52 | Go to google - should not load 53 |
54 | 55 |
56 |
57 | 58 |
59 |
60 | 61 |
62 |
63 | 64 | 65 | -------------------------------------------------------------------------------- /demo-snippets/ng/basic-example/basic-example.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /demo-snippets/ng/basic-example/basic-example.component.scss: -------------------------------------------------------------------------------- 1 | .label { 2 | font-size: 35; 3 | text-align: center; 4 | width: 100%; 5 | vertical-alignment: center; 6 | color: #FFFFFF; 7 | text-transform: uppercase; 8 | } -------------------------------------------------------------------------------- /demo-snippets/ng/basic-example/basic-example.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { RouterExtensions } from '@nativescript/angular'; 3 | 4 | @Component({ 5 | selector: 'ns-basic-example', 6 | templateUrl: './basic-example.component.html', 7 | styleUrls: ['./basic-example.component.scss'] 8 | }) 9 | export class BasicExampleComponent implements OnInit { 10 | constructor(private router: RouterExtensions) {} 11 | 12 | ngOnInit(): void {} 13 | 14 | goBack(): void { 15 | this.router.back(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demo-snippets/ng/install.module.ts: -------------------------------------------------------------------------------- 1 | import { NO_ERRORS_SCHEMA, NgModule } from '@angular/core'; 2 | 3 | import { AWebViewModule } from '@nativescript-community/ui-webview/angular'; 4 | import { BasicExampleComponent } from './basic-example/basic-example.component'; 5 | 6 | export const COMPONENTS = [BasicExampleComponent]; 7 | @NgModule({ 8 | imports: [AWebViewModule], 9 | exports: [AWebViewModule], 10 | schemas: [NO_ERRORS_SCHEMA] 11 | }) 12 | export class InstallModule {} 13 | 14 | export function installPlugin() {} 15 | 16 | export const demos = [{ name: 'Static Example', path: 'static-example', component: BasicExampleComponent }]; 17 | -------------------------------------------------------------------------------- /demo-snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/template-snippet", 3 | "private": true, 4 | "version": "0.0.1", 5 | "dependencies": { 6 | "@nativescript-community/perms": "2.2.21", 7 | "@nativescript-community/ui-webview": "*", 8 | "@nativescript-community/ui-webview-rtc": "*", 9 | "fast-deep-equal": "3.1.3", 10 | "url": "0.11.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /demo-snippets/react/BasicExample.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function BasicExample() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /demo-snippets/react/install.ts: -------------------------------------------------------------------------------- 1 | import { BasicPager } from './BasicExample'; 2 | 3 | export function installPlugin() { } 4 | 5 | export const demos = [ 6 | { name: 'Basic Pager', path: 'basic', component: BasicPager } 7 | ]; 8 | -------------------------------------------------------------------------------- /demo-snippets/svelte/BasicExample.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | goBack()} /> 8 | 9 | 10 | 11 | 12 | 22 | -------------------------------------------------------------------------------- /demo-snippets/svelte/install.ts: -------------------------------------------------------------------------------- 1 | import BasicExample from './BasicExample.svelte'; 2 | import installWebRTC from '@nativescript-community/ui-webview-rtc'; 3 | 4 | export function installPlugin() { 5 | installWebRTC(); 6 | } 7 | 8 | export const demos = [{ name: 'Basic Example', path: 'basic', component: BasicExample }]; 9 | -------------------------------------------------------------------------------- /demo-snippets/vue/install.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'nativescript-vue'; 2 | import WebView from '@nativescript-community/ui-webview/vue'; 3 | import {WebViewTraceCategory} from '@nativescript-community/ui-webview'; 4 | import {Trace} from '@nativescript/core'; 5 | import installWebRTC from '@nativescript-community/ui-webview-rtc'; 6 | 7 | import BasicExample from './BasicExample.vue'; 8 | 9 | export function installPlugin() { 10 | Trace.addCategories(WebViewTraceCategory); 11 | Trace.enable(); 12 | installWebRTC(); 13 | Vue.use(WebView); 14 | } 15 | 16 | export const demos = [{ name: 'Basic Example', path: 'basic', component: BasicExample }]; 17 | -------------------------------------------------------------------------------- /detox.config.js: -------------------------------------------------------------------------------- 1 | const devices = require('./devices'); 2 | 3 | module.exports = { 4 | testRunner: 'jest', 5 | runnerConfig: 'e2e/config.json', 6 | configurations: { 7 | 'ng.ios': { 8 | binaryPath: 'demo-ng/platforms/ios/build/Debug-iphonesimulator/demong.app', 9 | build: 'cd demo-ng && ns build ios', 10 | type: 'ios.simulator', 11 | device: { 12 | type: devices.ios, 13 | }, 14 | }, 15 | 'ng.android': { 16 | binaryPath: 'demo-ng/platforms/android/app/build/outputs/apk/debug/app-debug.apk', 17 | build: 'cd demo-ng && ns build android --detox', 18 | type: 'android.emulator', 19 | device: { 20 | avdName: devices.android, 21 | }, 22 | }, 23 | 'vue.ios': { 24 | binaryPath: 'demo-vue/platforms/ios/build/Debug-iphonesimulator/demovue.app', 25 | build: 'cd demo-vue && ns build ios', 26 | type: 'ios.simulator', 27 | device: { 28 | type: devices.ios, 29 | }, 30 | }, 31 | 'vue.android': { 32 | binaryPath: 'demo-vue/platforms/android/app/build/outputs/apk/debug/app-debug.apk', 33 | build: 'cd demo-vue && ns build android --detox', 34 | type: 'android.emulator', 35 | device: { 36 | avdName: devices.android, 37 | }, 38 | }, 39 | 'svelte.ios': { 40 | binaryPath: 'demo-svelte/platforms/ios/build/Debug-iphonesimulator/demosvelte.app', 41 | build: 'cd demo-svelte && ns build ios', 42 | type: 'ios.simulator', 43 | device: { 44 | type: devices.ios, 45 | }, 46 | }, 47 | 'svelte.android': { 48 | binaryPath: 'demo-svelte/platforms/android/app/build/outputs/apk/debug/app-debug.apk', 49 | build: 'cd demo-svelte && ns build android --detox', 50 | type: 'android.emulator', 51 | device: { 52 | avdName: devices.android, 53 | }, 54 | }, 55 | 'react.ios': { 56 | binaryPath: 'demo-react/platforms/ios/build/Debug-iphonesimulator/demoreact.app', 57 | build: 'cd demo-react && ns build ios', 58 | type: 'ios.simulator', 59 | device: { 60 | type: devices.ios, 61 | }, 62 | }, 63 | 'react.android': { 64 | binaryPath: 'demo-react/platforms/android/app/build/outputs/apk/debug/app-debug.apk', 65 | build: 'cd demo-react && ns build android --detox', 66 | type: 'android.emulator', 67 | device: { 68 | avdName: devices.android, 69 | }, 70 | }, 71 | }, 72 | }; 73 | -------------------------------------------------------------------------------- /devices.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ios: 'iPhone 12 Pro Max', 3 | android: 'Pixel_3a_API_30_1' 4 | }; 5 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/assets/hierarchy.js: -------------------------------------------------------------------------------- 1 | window.hierarchyData = "eJytlstSgzAUht8l61gLJIDdeakrZ3S8Lpwu0nJaMoagSVqdcfruhmo7QFFDdBEWJB//Nxw4yTtSZWk0Gj1SSjGhwQQjBXMBM8NLae+/I1pdJCsAjdDxA0zvObwijJ64zNAoCFOMlkrYuZlgWoM+fIXpyi4ZbNcOclMIC2zm7Tqjs4MKPvi8scbIxtYyvrDxmxmvQJozZtguLqTxNo5LA2rOZrXEDvLb8B1eTeZcZAqkfQuERpikMSZHgR0xpkOCaWBHGGEahXYkmJKhHfFkYx7VzC9KlvV1bjD9bVNMYoJJMvy0SVs2N4YpA15SbdTBrVKISUvhnEuucz+HPdZRIhnWJG7ycimyyxUoxTO4U8KnTD8/pHfdknRTryTt9PwPTT/LSiqNWxW8UuVCgdY+FdxjHSWO6h3hlhsBpzmTi/6fUSfrKhE329KxAOXTlJqcW7htPM1w+yaLZ5/0FugYH7TiT0s556rwyG+TjgJhtCegSwF+Ag3SUSAKawLX8LIEba5AFVzramvsK/LDE1yFko5d0nOL7BlN6g11XE2dL4XQMwUg+yp8h7uq1H/K8Rs3fzDpph1FKO08tJwwDS7HoybxyyGpsXvQyXq9/gDqJksx" -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #795E26; 3 | --dark-hl-0: #DCDCAA; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #A31515; 7 | --dark-hl-2: #CE9178; 8 | --light-hl-3: #AF00DB; 9 | --dark-hl-3: #C586C0; 10 | --light-hl-4: #001080; 11 | --dark-hl-4: #9CDCFE; 12 | --light-hl-5: #008000; 13 | --dark-hl-5: #6A9955; 14 | --light-hl-6: #000000; 15 | --dark-hl-6: #C8C8C8; 16 | --light-code-background: #FFFFFF; 17 | --dark-code-background: #1E1E1E; 18 | } 19 | 20 | @media (prefers-color-scheme: light) { :root { 21 | --hl-0: var(--light-hl-0); 22 | --hl-1: var(--light-hl-1); 23 | --hl-2: var(--light-hl-2); 24 | --hl-3: var(--light-hl-3); 25 | --hl-4: var(--light-hl-4); 26 | --hl-5: var(--light-hl-5); 27 | --hl-6: var(--light-hl-6); 28 | --code-background: var(--light-code-background); 29 | } } 30 | 31 | @media (prefers-color-scheme: dark) { :root { 32 | --hl-0: var(--dark-hl-0); 33 | --hl-1: var(--dark-hl-1); 34 | --hl-2: var(--dark-hl-2); 35 | --hl-3: var(--dark-hl-3); 36 | --hl-4: var(--dark-hl-4); 37 | --hl-5: var(--dark-hl-5); 38 | --hl-6: var(--dark-hl-6); 39 | --code-background: var(--dark-code-background); 40 | } } 41 | 42 | :root[data-theme='light'] { 43 | --hl-0: var(--light-hl-0); 44 | --hl-1: var(--light-hl-1); 45 | --hl-2: var(--light-hl-2); 46 | --hl-3: var(--light-hl-3); 47 | --hl-4: var(--light-hl-4); 48 | --hl-5: var(--light-hl-5); 49 | --hl-6: var(--light-hl-6); 50 | --code-background: var(--light-code-background); 51 | } 52 | 53 | :root[data-theme='dark'] { 54 | --hl-0: var(--dark-hl-0); 55 | --hl-1: var(--dark-hl-1); 56 | --hl-2: var(--dark-hl-2); 57 | --hl-3: var(--dark-hl-3); 58 | --hl-4: var(--dark-hl-4); 59 | --hl-5: var(--dark-hl-5); 60 | --hl-6: var(--dark-hl-6); 61 | --code-background: var(--dark-code-background); 62 | } 63 | 64 | .hl-0 { color: var(--hl-0); } 65 | .hl-1 { color: var(--hl-1); } 66 | .hl-2 { color: var(--hl-2); } 67 | .hl-3 { color: var(--hl-3); } 68 | .hl-4 { color: var(--hl-4); } 69 | .hl-5 { color: var(--hl-5); } 70 | .hl-6 { color: var(--hl-6); } 71 | pre, code { background: var(--code-background); } 72 | -------------------------------------------------------------------------------- /docs/assets/navigation.js: -------------------------------------------------------------------------------- 1 | window.navigationData = "eJylmFtT2zAQhf9LnumNFtryloQwE1pohgSYKcODIm9iFVlydQnJdPrfK4cQ3+L1evqKz/mOLK02ix/+9BysXe+s9wzzlYDn3lEvZS4Of0h05CXYd7sHb2OXyPD0Saiod3Z81OOxkJEB1Tt72ENGK1DumiVgcw4on+SUXFEGfvl7tKf072F+V1oLl8zawlpeFWXGh+Mi5VZZn6baOIim599GxmjTDDwgxti7+NHaDZiFZmxZhxFHyoG58FJabgDUdpvOmWM5W2SKBeMFfJOpclYnp8WgtXCdcw57sJix+gXcjdbAvYNLtmJTbkTq0JgGDxbzXbOI9g4lZRvyQihhY+iArjnaIvL3uwGrveHQmlG3tIVMjF4asJb+HjVHW8TUsezW0BOqhvaAjYRpDEDfqLoFC7mB3x6sm4BJhLVCK+J2IT4sbhprL6MfKzAiglsj6SWMOmmR/5HZNXQmnIRhzNSSWh0HHVhE1lsnoWmHok3BOFH82TnAr8sxeOjdfRlktLXX1C3ooVYLYRIyvKpvx1stoQu+pG/Bhx1MUvrOVOQt8O0vJhVdElPAa/qyq3oMP2Q8hisdFZqT26QF3l5Qobz/+vnDyXGBdM1WYslc6CezAGjClVVtzNfKv2PSNyJLojYik1I/27GSQsEVRIJNJNvMGX/aXa5NnrJiRrB5cZRsNZfTP5aCvdMvg8LldBB60hJIiY0uJGruhXRj9VPrJNwPZ7S0lCzEhoTx1/qgRNTEGNhbp5NbC6a/DIVMwh+2ICFRuB7zMOJOnTaMdiQNFiwE5n5J3aKaGAMLm4YK7HrQiA0L00mXXaqpEbSwYTzUUo5UBoko/AYLEiJFIpzN+4+d6X6aDrRX0blOmFCkvaNTkKUkxd6RjWMijK7bsuUZk7IOIgJZhOUsACfhhGb6QpDuV4MFDckOacDMWEWCs1ARd8KKAKXFtZjbg8O58C5ZJT2GN5xEzWUY7OVf+Ow+kqB1OQL3Fu7DBFyZIdGABgsSsupAr2oR7PN+wKOA62oEvRuTZiYMT0PmYKkNCj+kr+Efy2vPjG+M443fprKHpO9TESyYl4WvEItQp9v2U0LtZGXk6aewrsd/gqDcYQ==" -------------------------------------------------------------------------------- /docs/types/webview.CacheMode.html: -------------------------------------------------------------------------------- 1 | CacheMode | @nativescript-community/ui-webview-root
CacheMode: "default" | "cache_first" | "no_cache" | "cache_only" | "normal"
2 | -------------------------------------------------------------------------------- /docs/types/webview.ViewPortValue.html: -------------------------------------------------------------------------------- 1 | ViewPortValue | @nativescript-community/ui-webview-root
ViewPortValue: boolean | ViewPortProperties
2 | -------------------------------------------------------------------------------- /docs/variables/webview.WebViewTraceCategory.html: -------------------------------------------------------------------------------- 1 | WebViewTraceCategory | @nativescript-community/ui-webview-root
WebViewTraceCategory: "AWebView"
2 | -------------------------------------------------------------------------------- /docs/variables/webview.autoInjectJSBridgeProperty.html: -------------------------------------------------------------------------------- 1 | autoInjectJSBridgeProperty | @nativescript-community/ui-webview-root
autoInjectJSBridgeProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.builtInZoomControlsProperty.html: -------------------------------------------------------------------------------- 1 | builtInZoomControlsProperty | @nativescript-community/ui-webview-root
builtInZoomControlsProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.cacheModeProperty.html: -------------------------------------------------------------------------------- 1 | cacheModeProperty | @nativescript-community/ui-webview-root
cacheModeProperty: Property<WebViewExtBase, CacheMode>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.customUserAgentProperty.html: -------------------------------------------------------------------------------- 1 | customUserAgentProperty | @nativescript-community/ui-webview-root
customUserAgentProperty: Property<WebViewExtBase, string>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.databaseStorageProperty.html: -------------------------------------------------------------------------------- 1 | databaseStorageProperty | @nativescript-community/ui-webview-root
databaseStorageProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.debugModeProperty.html: -------------------------------------------------------------------------------- 1 | debugModeProperty | @nativescript-community/ui-webview-root
debugModeProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.domStorageProperty.html: -------------------------------------------------------------------------------- 1 | domStorageProperty | @nativescript-community/ui-webview-root
domStorageProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.isScrollEnabledProperty.html: -------------------------------------------------------------------------------- 1 | isScrollEnabledProperty | @nativescript-community/ui-webview-root
isScrollEnabledProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.scalesPageToFitProperty.html: -------------------------------------------------------------------------------- 1 | scalesPageToFitProperty | @nativescript-community/ui-webview-root
scalesPageToFitProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.scrollBounceProperty.html: -------------------------------------------------------------------------------- 1 | scrollBounceProperty | @nativescript-community/ui-webview-root
scrollBounceProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.srcProperty.html: -------------------------------------------------------------------------------- 1 | srcProperty | @nativescript-community/ui-webview-root
srcProperty: Property<WebViewExtBase, string>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.supportZoomProperty.html: -------------------------------------------------------------------------------- 1 | supportZoomProperty | @nativescript-community/ui-webview-root
supportZoomProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.useWideViewPortProperty.html: -------------------------------------------------------------------------------- 1 | useWideViewPortProperty | @nativescript-community/ui-webview-root
useWideViewPortProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /docs/variables/webview.webConsoleProperty.html: -------------------------------------------------------------------------------- 1 | webConsoleProperty | @nativescript-community/ui-webview-root
webConsoleProperty: Property<WebViewExtBase, boolean>
2 | -------------------------------------------------------------------------------- /e2e/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "testEnvironment": "./environment", 3 | "testRunner": "jest-circus/runner", 4 | "testTimeout": 120000, 5 | "testRegex": "\\.e2e\\.js$", 6 | "reporters": ["detox/runners/jest/streamlineReporter"], 7 | "verbose": true 8 | } 9 | -------------------------------------------------------------------------------- /e2e/environment.js: -------------------------------------------------------------------------------- 1 | const { DetoxCircusEnvironment, SpecReporter, WorkerAssignReporter } = require('detox/runners/jest-circus'); 2 | 3 | class CustomDetoxEnvironment extends DetoxCircusEnvironment { 4 | constructor(config) { 5 | super(config); 6 | 7 | // Can be safely removed, if you are content with the default value (=300000ms) 8 | this.initTimeout = 300000; 9 | 10 | // This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level. 11 | // This is strictly optional. 12 | this.registerListeners({ 13 | SpecReporter, 14 | WorkerAssignReporter, 15 | }); 16 | } 17 | } 18 | 19 | module.exports = CustomDetoxEnvironment; 20 | -------------------------------------------------------------------------------- /e2e/run-tests.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const { spawn } = require('child_process'); 3 | const { argv } = require('yargs') 4 | .scriptName('run-tests') 5 | .usage('Usage: $0 -p num -h num') 6 | .example('$0', 'Builds and runs e2e testing on all supported platforms and frameworks.') 7 | .example('$0 -b', 'Build e2e testing for all supported platforms and frameworks.') 8 | .example('$0 -r', 'Run e2e testing for all supported platforms and frameworks.') 9 | .example('$0 -p ios', 'Builds and runs e2e testing for all frameworks only on iOS.') 10 | .example('$0 -f ng vue', 'Builds an d runs e2e testing on Angular and Vue.js.') 11 | .example('$0 -p android -f svelte', 'Builds and runs e2e testing for Svelte on iOS.') 12 | .option('p', { 13 | alias: 'platforms', 14 | default: ['ios', 'android'], 15 | choices: ['ios', 'android'], 16 | describe: 'The platforms to test on.', 17 | type: 'array', 18 | }) 19 | .option('f', { 20 | alias: 'frameworks', 21 | default: ['ng', 'vue', 'svelte', 'react'], 22 | choices: ['ng', 'vue', 'svelte', 'react'], 23 | describe: 'The frameworks to test on.', 24 | type: 'array', 25 | }) 26 | .option('b', { 27 | alias: 'build', 28 | default: false, 29 | describe: 'Flag to ONLY run building of the projects.', 30 | type: 'boolean', 31 | }) 32 | .option('r', { 33 | alias: 'run', 34 | default: false, 35 | describe: 'Flag to ONLY run testing (no building) of the projects.', 36 | type: 'boolean', 37 | }); 38 | 39 | const { platforms, frameworks, build, run } = argv; 40 | command = generateDetoxCommand(platforms, frameworks, build, run); 41 | 42 | console.log(command); 43 | 44 | function generateDetoxCommand(platforms, frameworks, build, run) { 45 | 46 | configurations = []; 47 | for (const platform of platforms) { 48 | for (const framework of frameworks) { 49 | configurations.push(`${framework}.${platform}`); 50 | } 51 | } 52 | 53 | configurations.sort(); 54 | 55 | commands = []; 56 | if (!build && !run) { 57 | for (const configuration of configurations) { 58 | commands.push(`detox build -c ${configuration} && detox test -c ${configuration}`); 59 | } 60 | } 61 | else if(build) { 62 | for (const configuration of configurations) { 63 | commands.push(`detox build -c ${configuration}`); 64 | } 65 | } 66 | else if(run) { 67 | for (const configuration of configurations) { 68 | commands.push(`detox test -c ${configuration}`); 69 | } 70 | } 71 | else { 72 | for (const configuration of configurations) { 73 | commands.push(`detox build -c ${configuration} && detox test -c ${configuration}`); 74 | } 75 | } 76 | 77 | let combinedCommand = ''; 78 | for (let i=0; i { 93 | process.stdout.write(`${data}`); 94 | }); 95 | 96 | ls.stderr.on('data', (data) => { 97 | process.stderr.write(`${data}`); 98 | }); 99 | 100 | ls.on('error', (error) => { 101 | console.log(`error: ${error.message}`); 102 | }); 103 | 104 | ls.on('close', (code) => { 105 | console.log(`child process exited with code ${code}`); 106 | }); 107 | 108 | -------------------------------------------------------------------------------- /e2e/tests.e2e.js: -------------------------------------------------------------------------------- 1 | describe('Scroll Test', () => { 2 | beforeEach(async () => { 3 | await device.reloadReactNative(); 4 | }); 5 | 6 | const firstElement = 'TURQUOISE'; 7 | const lastElement = 'ASBESTOS'; 8 | 9 | it(`${firstElement} should be visible`, async () => { 10 | await expect(element(by.text(firstElement))).toBeVisible(); 11 | }); 12 | 13 | it(`${lastElement} should not be visible`, async () => { 14 | await expect(element(by.text(lastElement))).not.toBeVisible(); 15 | }); 16 | 17 | it('should scroll to bottom', async () => { 18 | await element(by.label('collectionView')).scrollTo('bottom'); 19 | }); 20 | 21 | it(`${lastElement} should be visible`, async () => { 22 | await expect(element(by.text(lastElement))).toBeVisible(); 23 | }); 24 | 25 | it(`${firstElement} should not be visible`, async () => { 26 | await expect(element(by.text(firstElement))).not.toBeVisible(); 27 | }); 28 | 29 | it('should scroll to top', async () => { 30 | await element(by.label('collectionView')).scrollTo('top'); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /images/demo-android.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/images/demo-android.gif -------------------------------------------------------------------------------- /images/demo-ios.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/images/demo-ios.gif -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.2", 3 | "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json", 4 | "packages": [ 5 | "packages/*" 6 | ], 7 | "npmClient": "yarn", 8 | "useWorkspaces": true, 9 | "command": { 10 | "publish": { 11 | "cleanupTempFiles": true 12 | } 13 | }, 14 | "npmClientArgs": [ 15 | "--no-package-lock" 16 | ], 17 | "commitHooks": false, 18 | "createRelease": "github", 19 | "conventionalCommits": true, 20 | "private": false, 21 | "message": "chore(release): publish new version %v", 22 | "changelogPreset": "conventional-changelog-conventionalcommits", 23 | "ignoreChanges": [ 24 | "**/__fixtures__/**", 25 | "**/__tests__/**", 26 | "**/*.md" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /make-bridge-loader.ts: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const Terser = require('terser'); 3 | const { promisify } = require('util'); 4 | 5 | const fsWriteFile = promisify(fs.writeFile); 6 | const fsReadFile = promisify(fs.readFile); 7 | 8 | async function nativescriptWebviewBridgeLoader(platform: 'ios' | 'android') { 9 | let template = await fsReadFile(`./www-src/bridge-loader.${platform}.ts.tmpl`, 'UTF-8'); 10 | 11 | const values = { 12 | // fetchPolyfill: await fsReadFile('./node_modules/whatwg-fetch/dist/fetch.umd.js', 'UTF-8'), 13 | // promisePolyfill: await fsReadFile('./www-src/node_modules/promise-polyfill/dist/polyfill.js', 'UTF-8'), 14 | webViewBridge: await fsReadFile(`./build/bridge.${platform}.js`, 'UTF-8'), 15 | metadataViewPort: await fsReadFile('./build/metadata-view-port.js', 'UTF-8'), 16 | }; 17 | 18 | for (const [name, value] of Object.entries(values)) { 19 | const terserRes = await Terser.minify(value, { 20 | ecma: 2019, 21 | module: false, 22 | toplevel: false, 23 | keep_classnames: false, 24 | keep_fnames: false, 25 | compress: { 26 | passes: 2, 27 | drop_console: true 28 | }, 29 | mangle: { 30 | toplevel: true, 31 | properties: { 32 | regex: /^(m[A-Z])/ 33 | } 34 | } 35 | }); 36 | template = template.replace(``, JSON.stringify(terserRes.code)); 37 | } 38 | 39 | await fsWriteFile(`./src/webview/nativescript-webview-bridge-loader.${platform}.ts`, template); 40 | } 41 | 42 | async function worker() { 43 | await nativescriptWebviewBridgeLoader('ios'); 44 | await nativescriptWebviewBridgeLoader('android'); 45 | } 46 | 47 | worker(); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/ui-webview-root", 3 | "version": "1.0.0", 4 | "homepage": "https://github.com/nativescript-community/ui-webview#readme", 5 | "bugs": { 6 | "url": "https://github.com/nativescript-community/ui-webview/issues" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/nativescript-community/ui-webview.git" 11 | }, 12 | "license": "ISC", 13 | "author": "", 14 | "scripts": { 15 | "build": "lerna run build", 16 | "build.all": "lerna run build.all", 17 | "build.all.win": "lerna run build.all.win", 18 | "build.angular": "lerna run build.angular", 19 | "build.angular.win": "lerna run build.angular.win", 20 | "build.win": "lerna run build.win", 21 | "clean": "rimraf 'packages/**/*.d.ts' 'packages/**/*.js' 'packages/**/*.js.map' 'packages/**/*.metada' 'packages/**/angular/ng-package.json'", 22 | "clean.win": "rimraf packages\\**\\*.d.ts packages\\**\\*.js packages\\**\\*.js.map packages\\**\\*.metadata.json packages\\**\\*.ngsummary.json node_modules package-lock.json", 23 | "commitmsg": "commitlint -e $GIT_PARAMS", 24 | "demo.ng.android": "cd ./demo-ng && ns run android --no-hmr --env.watchNodeModules", 25 | "demo.ng.clean": "cd ./demo-ng && ns clean", 26 | "demo.ng.ios": "cd ./demo-ng && ns run ios --no-hmr --env.watchNodeModules", 27 | "demo.react.android": "cd ./demo-react && ns run android --no-hmr --env.watchNodeModules", 28 | "demo.react.clean": "cd ./demo-react && ns clean", 29 | "demo.react.ios": "cd ./demo-react && ns run ios --no-hmr --env.watchNodeModules", 30 | "demo.svelte.android": "cd ./demo-svelte && ns run android --no-hmr --env.watchNodeModules", 31 | "demo.svelte.clean": "cd ./demo-svelte && ns clean", 32 | "demo.svelte.ios": "cd ./demo-svelte && ns run ios --no-hmr --env.watchNodeModules", 33 | "demo.vue.android": "cd ./demo-vue && ns run android --no-hmr --env.watchNodeModules", 34 | "demo.vue.clean": "cd ./demo-vue && ns clean", 35 | "demo.vue.ios": "cd ./demo-vue && ns run ios --no-hmr --env.watchNodeModules", 36 | "postinstall": "npm run setup", 37 | "publish": "npm run setup && npm run clean && npm run build.all && npm run readme && npm run doc && npm run commit_readme_doc_changes && lerna publish", 38 | "readme": "lerna run readme && node ./tools/readme.js", 39 | "setup": "npm run submodules && ts-patch install", 40 | "start": "./node_modules/.bin/ntl -A -s 15 -o", 41 | "submodules": "git submodule update --init", 42 | "sync": "node ./tools/sync.js", 43 | "sync.test": "node ./tools/sync.js", 44 | "tsc": "cpy '**/*.d.ts' '../plugin' --parents --cwd=src && tsc -skipLibCheck -d", 45 | "update": "node ./tools/update.js", 46 | "watch": "npm run tsc -- -w", 47 | "doc": "node tools/builddoc.mjs", 48 | "fullclean": "npm run clean && rimraf 'packages/**/node_modules' 'demo-*/hooks' 'demo-*/node_modules' 'package-lock.json' 'pnpm-lock.yaml' 'node_modules'", 49 | "commit_readme_doc_changes": "git add docs/** *.md ; git commit -m \"readme/doc\" ; echo \"commit readme doc done\"" 50 | }, 51 | "commitlint": { 52 | "extends": [ 53 | "@commitlint/config-conventional" 54 | ] 55 | }, 56 | "dependencies": { 57 | "@nativescript-community/plugin-seed-tools": "file:tools", 58 | "@nativescript-community/template-snippet": "file:demo-snippets" 59 | }, 60 | "devDependencies": { 61 | "ts-node": "10.9.1" 62 | }, 63 | "ntl": { 64 | "descriptions": { 65 | "build": "Build the plugin", 66 | "build.angular": "Build the plugin for Angular", 67 | "build.all": "Build the plugin for all platforms", 68 | "clean": "Clean the local environment.", 69 | "demo.ng.android": "Runs the Angular demo on Android.", 70 | "demo.ng.ios": "Runs the Angular demo on iOS.", 71 | "demo.react.android": "Runs the React demo on Android.", 72 | "demo.react.ios": "Runs the React demo on iOS.", 73 | "demo.svelte.android": "Runs the Svelte demo on Android.", 74 | "demo.svelte.ios": "Runs the Svelte demo on iOS.", 75 | "demo.vue.android": "Runs the Vue demo on Android.", 76 | "demo.vue.ios": "Runs the Vue demo on iOS.", 77 | "watch": "Watch for changes in the plugin source and re-build." 78 | } 79 | }, 80 | "engines": { 81 | "npm": "please use yarn or pnpm", 82 | "yarn": ">=1.19.1", 83 | "pnpm": ">=7.0.0", 84 | "node": "^14.20.0 || ^16.13.0 || >=18.10.0" 85 | }, 86 | "workspaces": [ 87 | "packages/*", 88 | "demo*" 89 | ] 90 | } 91 | -------------------------------------------------------------------------------- /packages/webview-rtc/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tsconfig.json 3 | node_modules/ 4 | pnpm-global/ 5 | CHANGELOG.md 6 | blueprint.md 7 | *.aar 8 | *.jar -------------------------------------------------------------------------------- /packages/webview-rtc/README.md: -------------------------------------------------------------------------------- 1 | # NativeScript WebView RTC 2 | [![npm downloads](https://img.shields.io/npm/dm/@nativescript-community/ui-webview-rtc.svg)](https://www.npmjs.com/package/@nativescript-community/ui-webview-rtc) 3 | [![npm downloads](https://img.shields.io/npm/dt/@nativescript-community/ui-webview-rtc.svg)](https://www.npmjs.com/package/@nativescript-community/ui-webview-rtc) 4 | [![npm](https://img.shields.io/npm/v/@nativescript-community/ui-webview-rtc.svg)](https://www.npmjs.com/package/@nativescript-community/ui-webview-rtc) 5 | 6 | A NativeScript Plugin to add webRTC support to `@nativescript-community/ui-webview` 7 | 8 | ## Installation 9 | Run the following command from the root of your project: 10 | 11 | `tns plugin add @nativescript-community/ui-webview-rtc` 12 | 13 | This command automatically installs the necessary files, as well as stores @nativescript-community/ui-webview-rtc as a dependency in your project's package.json file. 14 | 15 | ## Configuration 16 | 17 | To install the plugin run 18 | ```typescript 19 | import install from '@nativescript-community/ui-webview-rtc'; 20 | install(); 21 | ``` 22 | 23 | then simply use the `webRTC="true"` as a webview property 24 | -------------------------------------------------------------------------------- /packages/webview-rtc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/ui-webview-rtc", 3 | "version": "1.5.2", 4 | "main": "./index", 5 | "sideEffects": false, 6 | "typings": "./index.d.ts", 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/nativescript-community/ui-collectionview.git" 10 | }, 11 | "scripts": { 12 | "build": "npm run tsc", 13 | "build.all": "npm run build", 14 | "tsc": "cpy '**/*.d.ts' '../../packages/webview-rtc' --parents --cwd=../../src/webview-rtc && tsc -skipLibCheck -d", 15 | "clean": "rimraf ./*.d.ts ./*.js ./*.js.map" 16 | }, 17 | "nativescript": { 18 | "platforms": { 19 | "android": "6.1.0", 20 | "ios": "6.1.0" 21 | } 22 | }, 23 | "keywords": [ 24 | "NativeScript", 25 | "JavaScript", 26 | "Android", 27 | "iOS" 28 | ], 29 | "author": { 30 | "name": "Martin Guillon", 31 | "email": "martin@akylas.fr" 32 | }, 33 | "license": "ISC", 34 | "bugs": { 35 | "url": "https://github.com/nativescript-community/ui-webview/issues" 36 | }, 37 | "homepage": "https://github.com/nativescript-community/ui-webview#readme", 38 | "dependencies": { 39 | "@nativescript-community/ui-webview": "^1.5.2" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/webview-rtc/platforms/ios/Podfile: -------------------------------------------------------------------------------- 1 | pod 'WKWebViewRTC', :git => 'https://github.com/farfromrefug/WKWebViewRTC.git', :branch => 'dev' -------------------------------------------------------------------------------- /packages/webview-rtc/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "../../src/webview-rtc", 5 | "outDir": "./", 6 | "paths": { 7 | "@nativescript-community/ui-webview": ["packages/webview/index"], 8 | "@nativescript-community/ui-webview/*": ["packages/webview/*"] 9 | } 10 | }, 11 | "include": ["../../src/webview-rtc/**/*.ts", "../../references.d.ts", "../../tools/references.d.ts", "../../src/references.d.ts"], 12 | "exclude": ["../../src/webview-rtc/angular/**"] 13 | } 14 | -------------------------------------------------------------------------------- /packages/webview/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tsconfig.json 3 | node_modules/ 4 | pnpm-global/ 5 | CHANGELOG.md 6 | blueprint.md 7 | *.aar 8 | *.jar -------------------------------------------------------------------------------- /packages/webview/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/ui-webview", 3 | "version": "1.5.2", 4 | "description": "Advanced WebView plugin for NativeScript", 5 | "main": "./index", 6 | "sideEffects": false, 7 | "typings": "./index.d.ts", 8 | "scripts": { 9 | "build": "npm run build.www && npm run tsc", 10 | "build.www": " cd ../../www-src && rollup -c && cd .. && ts-node make-bridge-loader", 11 | "build.all": "npm run build && npm run build.angular", 12 | "build.angular": "ng-packagr -p ../../src/webview/angular/ng-package.json -c ../../src/webview/angular/tsconfig.json && rm angular/.npmignore", 13 | "tsc": "cpy '**/*.d.ts' '../../packages/webview' --parents --cwd=../../src/webview && tsc -skipLibCheck -d", 14 | "clean": "rimraf ./*.d.ts ./*.js ./*.js.map" 15 | }, 16 | "nativescript": { 17 | "platforms": { 18 | "android": "6.0.0", 19 | "ios": "6.0.0" 20 | } 21 | }, 22 | "keywords": [ 23 | "NativeScript", 24 | "JavaScript", 25 | "Android", 26 | "iOS", 27 | "webview", 28 | "WebView", 29 | "cache", 30 | "NativeScript UI", 31 | "nativescript community", 32 | "Angular", 33 | "Vue.js", 34 | "Vue.js Native", 35 | "Vue Native", 36 | "Svelte", 37 | "Svelte Native", 38 | "React", 39 | "React NativeScript", 40 | "preview|https://raw.githubusercontent.com/nativescript-community/ui-webview/master/images/demo-ios.gif|iOS Demo", 41 | "preview|https://raw.githubusercontent.com/nativescript-community/ui-webview/master/images/demo-android.gif|Android Demo" 42 | ], 43 | "author": { 44 | "name": "Nota", 45 | "email": "app@nota.dk", 46 | "url": "https://nota.dk" 47 | }, 48 | "contributors": [ 49 | { 50 | "name": "Martin Guillon", 51 | "email": "martin@akylas.fr" 52 | }, 53 | { 54 | "name": "Morten Anton Bach Sjøgren", 55 | "url": "http://mabs.dk", 56 | "email": "m_abs@mabs.dk" 57 | }, 58 | { 59 | "name": "Daniel Dam Freiling", 60 | "email": "dfg@nota.dk" 61 | } 62 | ], 63 | "bugs": { 64 | "url": "https://github.com/nativescript-community/ui-webview/issues" 65 | }, 66 | "repository": { 67 | "type": "git", 68 | "url": "https://github.com/nativescript-community/ui-webview" 69 | }, 70 | "license": "Apache-2.0", 71 | "readmeFilename": "README.md", 72 | "dependencies": { 73 | "url": "^0.11.0" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/webview/platforms/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /packages/webview/platforms/android/buildscript.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/packages/webview/platforms/android/buildscript.gradle -------------------------------------------------------------------------------- /packages/webview/platforms/android/include.gradle: -------------------------------------------------------------------------------- 1 | 2 | dependencies { 3 | implementation 'androidx.core:core:1.7.0' 4 | } 5 | -------------------------------------------------------------------------------- /packages/webview/platforms/android/java/com/nativescript/webviewinterface/WebChromeClient.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.webviewinterface; 2 | 3 | public class WebChromeClient extends android.webkit.WebChromeClient { 4 | boolean mConsoleEnabled ; 5 | 6 | public WebChromeClient() { 7 | super(); 8 | mConsoleEnabled = true; 9 | } 10 | public void setConsoleEnabled(boolean value) { 11 | mConsoleEnabled = value; 12 | } 13 | 14 | public boolean isConsoleEnabled() { 15 | return mConsoleEnabled; 16 | } 17 | public boolean onConsoleMessage(android.webkit.ConsoleMessage message) { 18 | if(mConsoleEnabled == false) { 19 | return true; 20 | } 21 | return handleConsoleMessage(message); 22 | } 23 | 24 | public boolean handleConsoleMessage(android.webkit.ConsoleMessage message) { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/webview/platforms/android/java/com/nativescript/webviewinterface/WebViewBridgeInterface.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.webviewinterface; 2 | 3 | import android.webkit.JavascriptInterface; 4 | 5 | public class WebViewBridgeInterface { 6 | public WebViewBridgeInterface() { 7 | } 8 | 9 | @JavascriptInterface 10 | public void emitEvent(String eventName, String data) { 11 | this.emitEventToNativeScript(eventName, data); 12 | } 13 | 14 | public void emitEventToNativeScript(String eventName, String data) { 15 | // Extend this function in nativescript 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/webview/platforms/android/native-api-usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "uses": [ 3 | "com.nativescript.webviewinterface:", 4 | "android.webkit:WebView", 5 | "android.webkit:WebViewClient", 6 | "android.webkit:WebChromeClient", 7 | "android.webkit:WebResourceRequest", 8 | "android.webkit:WebResourceResponse", 9 | "android.webkit:WebSettings", 10 | "android.webkit:JsResult", 11 | "android.webkit:ConsoleMessage", 12 | "android.webkit:ValueCallback", 13 | "android.webkit:PermissionRequest", 14 | "android.webkit:ConsoleMessage.MessageLevel" 15 | ] 16 | } -------------------------------------------------------------------------------- /packages/webview/platforms/ios/native-api-usage.json: -------------------------------------------------------------------------------- 1 | { 2 | "uses": [ 3 | "NativescriptWebViewExt*:*", 4 | "WebKit.WKURLSchemeHandler:*" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/webview/platforms/ios/src/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constants.swift 3 | // NotaWebViewExt 4 | // 5 | // Created by Morten Anton Bach Sjøgren on 14/01/2020. 6 | // Copyright © 2020 Morten Anton Bach Sjøgren. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Constants { 12 | static let customURLScheme = "x-local" 13 | 14 | static let mimeType: [String: String] = [ 15 | "html": "text/html", 16 | "htm": "text/html", 17 | "xhtml": "text/html", 18 | "xhtm": "text/html", 19 | "css": "text/css", 20 | "gif": "image/gif", 21 | "jpeg": "image/jpeg", 22 | "jpg": "image/jpeg", 23 | "js": "text/javascript", 24 | "otf": "application/vnd.ms-opentype", 25 | "png": "image/png", 26 | "svg": "image/svg+xml", 27 | "ttf": "application/x-font-ttf", 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /packages/webview/platforms/ios/src/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/packages/webview/platforms/ios/src/Info.plist -------------------------------------------------------------------------------- /packages/webview/platforms/ios/src/WKWebviewCustomSchemeHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WKWebviewCustomSchemeHandler.swift 3 | // NativescripWebViewExt 4 | // 5 | // Created by Morten Anton Bach Sjøgren on 14/01/2020. 6 | // Copyright © 2020 Morten Anton Bach Sjøgren. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import WebKit; 11 | 12 | enum WebErrors: Error { 13 | case RequestFailedError 14 | } 15 | 16 | @available(iOS 11, *) 17 | @objc 18 | public class CustomUrlSchemeHandler: NSObject,WKURLSchemeHandler { 19 | var resourceDict: [String: String] = [:]; 20 | 21 | @objc 22 | public func resolveFilePath(_ url: URL) -> String? { 23 | // NSLog("CustomUrlSchemeHandler.resolveFilePath(%@)", url.absoluteString); 24 | guard url.absoluteString.starts(with: Constants.customURLScheme) else { 25 | // NSLog("CustomUrlSchemeHandler.resolveFilePath(%@) - invalid scheme", url.absoluteString); 26 | return nil 27 | } 28 | let urlStr = url.host! + url.path 29 | guard let filepath = self.getRegisteredLocalResource(forKey: urlStr) else { 30 | // NSLog("CustomUrlSchemeHandler.resolveFilePath(%@) - no path", url.absoluteString); 31 | return nil; 32 | } 33 | 34 | // NSLog("CustomUrlSchemeHandler.resolveFilePath(%@) - path(%@) - filepath(%@)", url.absoluteString, urlStr, filepath); 35 | return filepath 36 | } 37 | 38 | @objc 39 | public func resolveMimeTypeFrom(filepath: String) -> String { 40 | let ext = URL(fileURLWithPath: filepath).pathExtension; 41 | // NSLog("CustomUrlSchemeHandler.resolveMimeTypeFrom(%@) - ext(%@)", filepath, ext) 42 | if let mimetype = Constants.mimeType[ext] { 43 | // NSLog("CustomUrlSchemeHandler.resolveMimeTypeFrom(%@) - ext(%@) -> mimetype(%@)", filepath, ext, mimetype) 44 | return mimetype 45 | } 46 | 47 | return "application/octet-stream" 48 | } 49 | 50 | @objc 51 | public func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { 52 | // NSLog("CustomUrlSchemeHandler"); 53 | DispatchQueue.global().async { 54 | // NSLog("CustomUrlSchemeHandler -> global async"); 55 | guard let url = urlSchemeTask.request.url, url.scheme == Constants.customURLScheme else { 56 | // NSLog("CustomUrlSchemeHandler - NO URL") 57 | urlSchemeTask.didFailWithError(WebErrors.RequestFailedError) 58 | return; 59 | } 60 | // NSLog("CustomUrlSchemeHandler - URL(%@)", url.absoluteString) 61 | guard let filepath = self.resolveFilePath(url) else { 62 | // NSLog("CustomUrlSchemeHandler - URL(%@) no path", url.absoluteString) 63 | urlSchemeTask.didFailWithError(WebErrors.RequestFailedError) 64 | return; 65 | } 66 | let mimeType = self.resolveMimeTypeFrom(filepath: filepath); 67 | // NSLog("CustomUrlSchemeHandler - URL(%@) path(%@)", url.absoluteString, filepath) 68 | guard let data = NSData.init(contentsOfFile: filepath) else { 69 | // NSLog("CustomUrlSchemeHandler - URL(%@) path(%@) no data", url.absoluteString, filepath) 70 | urlSchemeTask.didFailWithError(WebErrors.RequestFailedError) 71 | return; 72 | } 73 | 74 | let urlResponse = HTTPURLResponse.init(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: ["Content-Type": mimeType, "Access-Control-Allow-Origin": "*"]) 75 | 76 | urlSchemeTask.didReceive(urlResponse!) 77 | urlSchemeTask.didReceive(data as Data) 78 | urlSchemeTask.didFinish() 79 | } 80 | } 81 | 82 | @objc 83 | public func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) { 84 | urlSchemeTask.didFailWithError(WebErrors.RequestFailedError) 85 | } 86 | 87 | @objc 88 | public func registerLocalResource(forKey: String, filepath: String) { 89 | self.resourceDict[forKey] = filepath; 90 | } 91 | 92 | @objc 93 | public func unregisterLocalResource(forKey: String) { 94 | self.resourceDict.removeValue(forKey: forKey) 95 | } 96 | 97 | @objc 98 | public func getRegisteredLocalResource(forKey: String) -> String? { 99 | return self.resourceDict[forKey] 100 | } 101 | 102 | @objc 103 | public func clearRegisteredLocalResource() { 104 | self.resourceDict = [:] 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /packages/webview/platforms/ios/src/module.modulemap: -------------------------------------------------------------------------------- 1 | framework module NativescriptWebViewExt { 2 | umbrella header "NativescriptWebViewExt.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | 8 | module NativescriptWebViewExt.Swift { 9 | header "NativescriptWebViewExt-Swift.h" 10 | requires objc 11 | } 12 | -------------------------------------------------------------------------------- /packages/webview/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "../../src/webview", 5 | "outDir": "./" 6 | }, 7 | "include": ["../../src/webview/**/*.ts", "../../references.d.ts", "../../tools/references.d.ts", "../../src/references.d.ts"], 8 | "exclude": ["../../src/webview/angular/**"] 9 | } 10 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - packages/* 3 | - demo-* -------------------------------------------------------------------------------- /references.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/references.d.ts -------------------------------------------------------------------------------- /src-native/webview/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /src-native/webview/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | 19 | 1627552108089 20 | 21 | 30 22 | 23 | org.eclipse.core.resources.regexFilterMatcher 24 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src-native/webview/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.8)) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /src-native/webview/android/app/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src-native/webview/android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /src-native/webview/android/app/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | app 4 | Project app created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1627552108093 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src-native/webview/android/app/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir=.. 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /src-native/webview/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: "kotlin-kapt" 4 | 5 | android { 6 | compileOptions { 7 | sourceCompatibility JavaVersion.VERSION_1_8 8 | targetCompatibility JavaVersion.VERSION_1_8 9 | } 10 | compileSdkVersion 30 11 | defaultConfig { 12 | applicationId "com.nativescript.imagedemo" 13 | minSdkVersion 19 14 | targetSdkVersion 30 15 | versionCode 1 16 | versionName "1.0" 17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 18 | } 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | buildFeatures { 26 | viewBinding { 27 | enabled = true 28 | } 29 | dataBinding { 30 | enabled = true 31 | } 32 | } 33 | } 34 | 35 | dependencies { 36 | implementation fileTree(dir: 'libs', include: ['*.jar']) 37 | implementation 'androidx.appcompat:appcompat:1.0.0' 38 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 39 | testImplementation 'junit:junit:4.12' 40 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' 42 | implementation 'com.squareup.okhttp3:okhttp:3.10.0' 43 | implementation 'com.github.bumptech.glide:okhttp3-integration:4.10.0' 44 | implementation 'jp.wasabeef:glide-transformations:4.1.0' 45 | implementation 'jp.co.cyberagent.android:gpuimage:2.0.3' 46 | implementation 'com.github.bumptech.glide:glide:4.11.0' 47 | kapt 'com.github.bumptech.glide:compiler:4.11.0' 48 | kapt 'androidx.annotation:annotation:1.1.0' 49 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 50 | implementation project(path: ':image') 51 | implementation "androidx.core:core-ktx:+" 52 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 53 | } 54 | repositories { 55 | mavenCentral() 56 | } 57 | -------------------------------------------------------------------------------- /src-native/webview/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/androidTest/java/com/github/triniwiz/imagedemo/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.nativescript.imagedemo 2 | 3 | import android.content.Context 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | import androidx.test.platform.app.InstrumentationRegistry 6 | import org.junit.Assert 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | 10 | /** 11 | * Instrumented test, which will execute on an Android device. 12 | * 13 | * @see [Testing documentation](http://d.android.com/tools/testing) 14 | */ 15 | @RunWith(AndroidJUnit4::class) 16 | class ExampleInstrumentedTest { 17 | @Test 18 | fun useAppContext() { 19 | // Context of the app under test. 20 | val appContext: Context = InstrumentationRegistry.getTargetContext() 21 | Assert.assertEquals("com.nativescript.imagedemo", appContext.packageName) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/java/com/nativescript/imagedemo/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.nativescript.imagedemo 2 | 3 | import android.app.Activity 4 | import android.graphics.Color 5 | import android.graphics.drawable.ColorDrawable 6 | import android.net.Uri 7 | import android.os.Bundle 8 | import android.os.Handler 9 | import android.util.Log 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import android.widget.TextView 14 | import androidx.appcompat.app.AppCompatActivity 15 | import androidx.recyclerview.widget.LinearLayoutManager 16 | import androidx.recyclerview.widget.RecyclerView 17 | import androidx.recyclerview.widget.RecyclerView.ViewHolder 18 | import com.bumptech.glide.Glide 19 | import com.nativescript.image.ImageView 20 | import com.nativescript.image.ImageView.Companion.enableAutoMM 21 | import com.nativescript.imagedemo.databinding.ActivityMainBinding 22 | import org.json.JSONArray 23 | import org.json.JSONException 24 | 25 | class MainActivity : AppCompatActivity() { 26 | lateinit var binding: ActivityMainBinding 27 | var list: JSONArray? = null 28 | fun dp(dp: Int): Int { 29 | return dp * resources.displayMetrics.density as Int 30 | } 31 | 32 | override fun onCreate(savedInstanceState: Bundle?) { 33 | list = Data.items 34 | binding = ActivityMainBinding.inflate(layoutInflater) 35 | super.onCreate(savedInstanceState) 36 | setContentView(binding.getRoot()) 37 | val recyclerView = binding.listView 38 | val adapter: Adapter = Adapter() 39 | recyclerView.adapter = adapter 40 | recyclerView.layoutManager = LinearLayoutManager(this) 41 | val activity: Activity = this 42 | recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { 43 | override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { 44 | super.onScrollStateChanged(recyclerView, newState) 45 | when (newState) { 46 | RecyclerView.SCROLL_STATE_SETTLING, RecyclerView.SCROLL_STATE_DRAGGING -> Glide.with(activity).pauseAllRequests() 47 | RecyclerView.SCROLL_STATE_IDLE -> Glide.with(activity).resumeRequests() 48 | } 49 | } 50 | 51 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { 52 | super.onScrolled(recyclerView, dx, dy) 53 | } 54 | }) 55 | enableAutoMM(application) 56 | } 57 | 58 | internal inner class Holder(itemView: View) : ViewHolder(itemView) { 59 | var imageView: ImageView? 60 | var foreground: ImageView? = null 61 | var textView: TextView? 62 | fun setText(text: String?) { 63 | textView?.setText(text) 64 | } 65 | 66 | init { 67 | imageView = itemView.findViewById(R.id.imageView) 68 | textView = itemView.findViewById(R.id.textView) 69 | // foreground = itemView.findViewById(R.id.imageView2) 70 | } 71 | } 72 | 73 | var handler: Handler? = Handler() 74 | 75 | internal inner class Adapter : RecyclerView.Adapter() { 76 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder { 77 | val inflater = LayoutInflater.from(parent.context) 78 | val view = inflater.inflate(R.layout.list_item, parent, false) 79 | return Holder(view) 80 | } 81 | 82 | override fun onBindViewHolder(holder: Holder, position: Int) { 83 | try { 84 | val json = list?.getJSONObject(position) 85 | val url = json?.optString("url") ?: "" 86 | //holder.imageView.setPlaceHolder("res://law"); 87 | // holder.imageView?.setPlaceHolder("res://placeholder_dark_grey_square") 88 | 89 | // holder.imageView.setErrorHolder("res://error"); 90 | // holder.imageView.setAdjustViewBounds(false); 91 | // holder.imageView.setScaleType(android.widget.ImageView.ScaleType.FIT_XY); 92 | holder.imageView?.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER) 93 | holder.imageView?.addBasicAuth("httpwatch", "httpwatch") 94 | if (position % 2 == 0) { 95 | holder.imageView?.priority = ImageView.Priority.Low 96 | } else { 97 | holder.imageView?.priority = ImageView.Priority.High 98 | } 99 | 100 | if (url.isNotEmpty()) { 101 | holder.imageView?.setSource(url) 102 | holder.textView?.text = url 103 | } else { 104 | holder.imageView?.setSource(null) 105 | holder.textView?.text = url 106 | } 107 | } catch (e: JSONException) { 108 | e.printStackTrace() 109 | } 110 | } 111 | 112 | override fun getItemCount(): Int { 113 | return list?.length() ?: 0 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/drawable/bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/drawable/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/drawable/error.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/drawable/law.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/drawable/law.jpg -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 14 | 23 | 24 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 18 | 19 | 36 | 37 | 48 | 49 | 50 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | #ff0000 7 | #ffffff 8 | #000000 9 | #007E00 10 | #0000ff 11 | #FF00F2 12 | 13 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ImageDemo 3 | 4 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src-native/webview/android/app/src/test/java/com/github/triniwiz/imagedemo/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package com.nativescript.imagedemo 2 | 3 | import org.junit.Assert 4 | import org.junit.Test 5 | 6 | /** 7 | * Example local unit test, which will execute on the development machine (host). 8 | * 9 | * @see [Testing documentation](http://d.android.com/tools/testing) 10 | */ 11 | class ExampleUnitTest { 12 | @Test 13 | fun addition_isCorrect() { 14 | Assert.assertEquals(4, (2 + 2).toLong()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src-native/webview/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.4.21' 5 | repositories { 6 | google() 7 | 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:4.1.1' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | google() 21 | 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | -------------------------------------------------------------------------------- /src-native/webview/android/gradle.properties: -------------------------------------------------------------------------------- 1 | ## For more details on how to configure your build environment visit 2 | # http://www.gradle.org/docs/current/userguide/build_environment.html 3 | # 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 8 | # 9 | # When configured, Gradle will run in incubating parallel mode. 10 | # This option should only be used with decoupled projects. More details, visit 11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 12 | # org.gradle.parallel=true 13 | #Fri Dec 18 13:51:47 AST 2020 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M" 17 | -------------------------------------------------------------------------------- /src-native/webview/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Dec 18 13:45:18 AST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip 7 | -------------------------------------------------------------------------------- /src-native/webview/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src-native/webview/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':webview' 3 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: "kotlin-kapt" 4 | 5 | android { 6 | compileSdkVersion 30 7 | buildToolsVersion "29.0.3" 8 | 9 | defaultConfig { 10 | minSdkVersion 17 11 | targetSdkVersion 30 12 | versionCode 1 13 | versionName "1.0" 14 | 15 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 16 | consumerProguardFiles 'consumer-rules.pro' 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 23 | } 24 | } 25 | 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | google() 31 | } 32 | 33 | dependencies { 34 | implementation fileTree(dir: 'libs', include: ['*.jar']) 35 | 36 | implementation 'androidx.appcompat:appcompat:1.0.0' 37 | testImplementation 'junit:junit:4.12' 38 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 39 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 40 | implementation 'com.squareup.okhttp3:okhttp:3.10.0' 41 | implementation 'com.github.bumptech.glide:okhttp3-integration:4.11.0' 42 | implementation 'jp.wasabeef:glide-transformations:4.1.0' 43 | implementation 'jp.co.cyberagent.android:gpuimage:2.0.3' 44 | implementation 'com.github.bumptech.glide:glide:4.11.0' 45 | kapt 'com.github.bumptech.glide:compiler:4.11.0' 46 | annotationProcessor 'androidx.annotation:annotation:1.1.0' 47 | implementation "androidx.core:core:1.3.2" 48 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 49 | } 50 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/consumer-rules.pro -------------------------------------------------------------------------------- /src-native/webview/android/webview/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/androidTest/java/com/nativescript/image/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.image; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | 25 | assertEquals("com.nativescript.image.test", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/java/com: -------------------------------------------------------------------------------- 1 | ../../../../../../../packages/webview/platforms/android/java/com -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable-hdpi/ic_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/src/main/res/drawable-hdpi/ic_indicator.png -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable-mdpi/ic_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/src/main/res/drawable-mdpi/ic_indicator.png -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable-xhdpi/ic_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/src/main/res/drawable-xhdpi/ic_indicator.png -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable-xxhdpi/ic_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/src/main/res/drawable-xxhdpi/ic_indicator.png -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable-xxxhdpi/ic_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativescript-community/ui-webview/4bfe01c7f40471450a91cca00cb6a6e4a3dea981/src-native/webview/android/webview/src/main/res/drawable-xxxhdpi/ic_indicator.png -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/drawable/progress_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src-native/webview/android/webview/src/test/java/com/nativescript/image/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.nativescript.image; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /src/webview-rtc/index.android.ts: -------------------------------------------------------------------------------- 1 | import { AWebView } from '@nativescript-community/ui-webview'; 2 | import { webRTCProperty } from './index.common'; 3 | export default function install() { 4 | AWebView.prototype[webRTCProperty.setNative] = function (enabled: boolean) {}; 5 | } 6 | -------------------------------------------------------------------------------- /src/webview-rtc/index.common.ts: -------------------------------------------------------------------------------- 1 | import { AWebView } from '@nativescript-community/ui-webview'; 2 | import { Property, booleanConverter } from '@nativescript/core'; 3 | 4 | export const webRTCProperty = new Property({ 5 | name: 'webRTC', 6 | defaultValue: false, 7 | valueConverter: booleanConverter 8 | }); 9 | 10 | webRTCProperty.register(AWebView); 11 | -------------------------------------------------------------------------------- /src/webview-rtc/index.d.ts: -------------------------------------------------------------------------------- 1 | export default function install(); 2 | 3 | declare module '@nativescript-community/ui-webview' { 4 | interface AWebView { 5 | webRTC: boolean; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/webview-rtc/index.ios.ts: -------------------------------------------------------------------------------- 1 | import { AWebView } from '@nativescript-community/ui-webview'; 2 | import { webRTCProperty } from './index.common'; 3 | export default function install() { 4 | AWebView.prototype[webRTCProperty.setNative] = function (enabled: boolean) { 5 | const nativeView = this.nativeViewProtected; 6 | if (!nativeView || this.webViewRTC) { 7 | return; 8 | } 9 | 10 | this.webViewRTC = WKWebViewRTC.alloc().initWithWkwebviewContentController(nativeView, nativeView.configuration.userContentController); 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /src/webview-rtc/types/ios/objc!WKWebViewRTC.d.ts: -------------------------------------------------------------------------------- 1 | 2 | declare class WKWebViewRTC extends NSObject implements WKScriptMessageHandler { 3 | 4 | static alloc(): WKWebViewRTC; // inherited from NSObject 5 | 6 | static new(): WKWebViewRTC; // inherited from NSObject 7 | 8 | readonly debugDescription: string; // inherited from NSObjectProtocol 9 | 10 | readonly description: string; // inherited from NSObjectProtocol 11 | 12 | readonly hash: number; // inherited from NSObjectProtocol 13 | 14 | readonly isProxy: boolean; // inherited from NSObjectProtocol 15 | 16 | readonly superclass: typeof NSObject; // inherited from NSObjectProtocol 17 | 18 | readonly // inherited from NSObjectProtocol 19 | 20 | constructor(o: { wkwebview: WKWebView; contentController: WKUserContentController; }); 21 | 22 | class(): typeof NSObject; 23 | 24 | conformsToProtocol(aProtocol: any /* Protocol */): boolean; 25 | 26 | dispose(): void; 27 | 28 | initWithWkwebviewContentController(wkwebview: WKWebView, contentController: WKUserContentController): this; 29 | 30 | isEqual(object: any): boolean; 31 | 32 | isKindOfClass(aClass: typeof NSObject): boolean; 33 | 34 | isMemberOfClass(aClass: typeof NSObject): boolean; 35 | 36 | performSelector(aSelector: string): any; 37 | 38 | performSelectorWithObject(aSelector: string, object: any): any; 39 | 40 | performSelectorWithObjectWithObject(aSelector: string, object1: any, object2: any): any; 41 | 42 | respondsToSelector(aSelector: string): boolean; 43 | 44 | retainCount(): number; 45 | 46 | self(): this; 47 | 48 | userContentControllerDidReceiveScriptMessage(userContentController: WKUserContentController, message: WKScriptMessage): void; 49 | } 50 | 51 | declare var WKWebViewRTCVersionNumber: number; 52 | 53 | declare var WKWebViewRTCVersionString: interop.Reference; 54 | -------------------------------------------------------------------------------- /src/webview/angular/index.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { NativeScriptCommonModule, isKnownView, registerElement } from '@nativescript/angular'; 3 | import { AWebView } from '@nativescript-community/ui-webview'; 4 | 5 | const webviewElementName = 'AWebView'; 6 | 7 | if (!isKnownView(webviewElementName)) { 8 | registerElement(webviewElementName, () => AWebView); 9 | } 10 | 11 | @NgModule({ 12 | imports: [NativeScriptCommonModule] 13 | }) 14 | export class AWebViewModule {} 15 | -------------------------------------------------------------------------------- /src/webview/angular/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dest": "../../../packages/webview/angular", 3 | "lib": { 4 | "entryFile": "index.ts" 5 | }, 6 | "allowedNonPeerDependencies": [ 7 | "." 8 | ] 9 | } -------------------------------------------------------------------------------- /src/webview/angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativescript-community/ui-webview-angular", 3 | "main": "index.js" 4 | } -------------------------------------------------------------------------------- /src/webview/angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "rootDir": "./", 5 | "plugins": [], 6 | "paths": { 7 | "@nativescript-community/ui-webview": ["packages/webview"], 8 | "@nativescript-community/ui-webview/*": ["packages/webview/*"] 9 | } 10 | }, 11 | "include": ["./**/*.ts", "../../../references.d.ts", "../references.d.ts"], 12 | "exclude": ["../node_modules"] 13 | } 14 | -------------------------------------------------------------------------------- /src/webview/index.d.ts: -------------------------------------------------------------------------------- 1 | import { WebViewExtBase } from './index.common'; 2 | export * from './index.common'; 3 | /** 4 | * Represents a standard WebView widget. 5 | */ 6 | export class AWebView extends WebViewExtBase {} 7 | -------------------------------------------------------------------------------- /src/webview/nativescript-webview-bridge-loader.android.ts: -------------------------------------------------------------------------------- 1 | 2 | export const webViewBridge: string = "class e{constructor(){this.t={}}onNativeEvent(e,t){const n=this.t[e];if(null==n?void 0:n.length)for(const e of n)if(!1===(null==e?void 0:e(t)))break}on(e,t){if(!t)return;let n=this.t[e];n||(n=this.t[e]=[]),n.push(t)}addEventListener(e,t){this.on(e,t)}off(e,t){if(!e)return void(this.t={});let n=this.t[e];n&&(t?(n=this.t[e]=n.filter((e=>e!==t)),0===n.length&&delete this.t[e]):delete this.t[e])}removeEventListener(e,t){return this.off(e,t)}emit(e,t){this.emitEvent(e,JSON.stringify(t))}async injectJavaScriptFile(e){const t=this.elementIdFromHref(e);if(!document.getElementById(t))return new Promise(((n,i)=>{const r=document.createElement(\"script\");r.async=!0,r.setAttribute(\"id\",t),r.addEventListener(\"error\",(e=>{i(this.serializeError(e)),r.parentElement&&r.parentElement.removeChild(r)})),r.addEventListener(\"load\",(function(){window.requestAnimationFrame((()=>{n()})),r.parentElement&&r.parentElement.removeChild(r)})),r.src=e,document.body.appendChild(r)}))}async injectJavaScript(e,t){if(!document.getElementById(e))return new Promise(((n,i)=>{const r=document.createElement(\"script\");r.setAttribute(\"id\",e),r.addEventListener(\"error\",(function(e){i(e),r.parentElement&&r.parentElement.removeChild(r)})),r.text=t,document.body.appendChild(r),window.requestAnimationFrame((()=>n()))}))}async injectStyleSheetFile(e,t){const n=this.elementIdFromHref(e);if(!document.getElementById(n))return new Promise(((i,r)=>{const o=document.createElement(\"link\");o.addEventListener(\"error\",(e=>{r(e),o.parentElement&&o.parentElement.removeChild(o)})),o.addEventListener(\"load\",(()=>{window.requestAnimationFrame((()=>{i()}))})),o.setAttribute(\"id\",n),o.setAttribute(\"rel\",\"stylesheet\"),o.setAttribute(\"type\",\"text/css\"),o.setAttribute(\"href\",e),document.head&&(t&&document.head.childElementCount>0?document.head.insertBefore(o,document.head.firstElementChild):document.head.appendChild(o))}))}async injectStyleSheet(e,t,n){if(!document.getElementById(e))return new Promise(((i,r)=>{var o;const s=document.createElement(\"style\");s.addEventListener(\"error\",r),s.textContent=t,s.setAttribute(\"id\",e);const d=null!==(o=document.head)&&void 0!==o?o:document.body;d?(n&&d.childElementCount>0?document.head.insertBefore(s,d.firstElementChild):document.head.appendChild(s),i()):r(new Error(\"Couldn't find parent element\"))}))}async executePromise(e,t){try{const n=await e;this.emit(t,{data:n})}catch(e){this.emitError(e,t)}}emitError(e,t=\"web-error\"){\"object\"==typeof e&&(null==e?void 0:e.message)?this.emit(t,{err:this.serializeError(e)}):this.emit(t,{err:e})}elementIdFromHref(e){return e.replace(/^[:]*:\\/\\//,\"\").replace(/[^a-z0-9]/g,\"\")}serializeError(e){const{name:t,message:n,stack:i,...r}=e;return Object.keys(r).reduce(((e,t)=>{const n=r[t];return n instanceof HTMLElement||(e[t]=n),e}),{name:t,message:n,stack:i})}}class t extends e{get androidWebViewBridge(){if(\"undefined\"!=typeof androidWebViewBridge)return androidWebViewBridge}emitEvent(e,t){this.androidWebViewBridge.emitEvent(e,t)}}const n=\"ns-bridge-ready\",i=window;if(!i.nsWebViewBridge){i.nsWebViewBridge=new t;for(const e of[n,\"ns-brige-ready\"])\"undefined\"!=typeof CustomEvent?window.dispatchEvent(new CustomEvent(e,{detail:i.nsWebViewBridge})):window.dispatchEvent(new Event(e))}"; 3 | export const metadataViewPort: string = "!function(e){const i={initialScale:1},a=e.document;let t=a.querySelector('head meta[name=\"viewport\"]');t||(t=a.createElement(\"meta\"),t.setAttribute(\"name\",\"viewport\"),a.head.appendChild(t));let l=\"<%= VIEW_PORT %>\";l&&\"string\"!=typeof l||(l=i);const{initialScale:n=i.initialScale,width:s,height:c,userScalable:m,minimumScale:o,maximumScale:u}=l,r=[`initial-scale=${n}`];if(s&&r.push(`width=${s}`),c&&r.push(`height=${c}`),\"boolean\"==typeof m)r.push(\"user-scalable=\"+(m?\"yes\":\"no\"));else if(\"string\"==typeof m){const e=`${m}`.toLowerCase();\"yes\"===e?r.push(\"user-scalable=yes\"):\"no\"===e&&r.push(\"user-scalable=no\")}o&&r.push(`minimum-scale=${o}`),u&&r.push(`maximum-scale=${u}`),t.setAttribute(\"content\",r.join(\", \"))}(window);"; 4 | -------------------------------------------------------------------------------- /src/webview/nativescript-webview-bridge-loader.d.ts: -------------------------------------------------------------------------------- 1 | export const webViewBridge: string; 2 | export const metadataViewPort: string; 3 | export const promisePolyfill: string; 4 | -------------------------------------------------------------------------------- /src/webview/nativescript-webview-bridge-loader.ios.ts: -------------------------------------------------------------------------------- 1 | 2 | export const webViewBridge: string = "class e{constructor(){this.t={}}onNativeEvent(e,t){const n=this.t[e];if(null==n?void 0:n.length)for(const e of n)if(!1===(null==e?void 0:e(t)))break}on(e,t){if(!t)return;let n=this.t[e];n||(n=this.t[e]=[]),n.push(t)}addEventListener(e,t){this.on(e,t)}off(e,t){if(!e)return void(this.t={});let n=this.t[e];n&&(t?(n=this.t[e]=n.filter((e=>e!==t)),0===n.length&&delete this.t[e]):delete this.t[e])}removeEventListener(e,t){return this.off(e,t)}emit(e,t){this.emitEvent(e,JSON.stringify(t))}async injectJavaScriptFile(e){const t=this.elementIdFromHref(e);if(!document.getElementById(t))return new Promise(((n,o)=>{const i=document.createElement(\"script\");i.async=!0,i.setAttribute(\"id\",t),i.addEventListener(\"error\",(e=>{o(this.serializeError(e)),i.parentElement&&i.parentElement.removeChild(i)})),i.addEventListener(\"load\",(function(){window.requestAnimationFrame((()=>{n()})),i.parentElement&&i.parentElement.removeChild(i)})),i.src=e,document.body.appendChild(i)}))}async injectJavaScript(e,t){if(!document.getElementById(e))return new Promise(((n,o)=>{const i=document.createElement(\"script\");i.setAttribute(\"id\",e),i.addEventListener(\"error\",(function(e){o(e),i.parentElement&&i.parentElement.removeChild(i)})),i.text=t,document.body.appendChild(i),window.requestAnimationFrame((()=>n()))}))}async injectStyleSheetFile(e,t){const n=this.elementIdFromHref(e);if(!document.getElementById(n))return new Promise(((o,i)=>{const r=document.createElement(\"link\");r.addEventListener(\"error\",(e=>{i(e),r.parentElement&&r.parentElement.removeChild(r)})),r.addEventListener(\"load\",(()=>{window.requestAnimationFrame((()=>{o()}))})),r.setAttribute(\"id\",n),r.setAttribute(\"rel\",\"stylesheet\"),r.setAttribute(\"type\",\"text/css\"),r.setAttribute(\"href\",e),document.head&&(t&&document.head.childElementCount>0?document.head.insertBefore(r,document.head.firstElementChild):document.head.appendChild(r))}))}async injectStyleSheet(e,t,n){if(!document.getElementById(e))return new Promise(((o,i)=>{var r;const s=document.createElement(\"style\");s.addEventListener(\"error\",i),s.textContent=t,s.setAttribute(\"id\",e);const c=null!==(r=document.head)&&void 0!==r?r:document.body;c?(n&&c.childElementCount>0?document.head.insertBefore(s,c.firstElementChild):document.head.appendChild(s),o()):i(new Error(\"Couldn't find parent element\"))}))}async executePromise(e,t){try{const n=await e;this.emit(t,{data:n})}catch(e){this.emitError(e,t)}}emitError(e,t=\"web-error\"){\"object\"==typeof e&&(null==e?void 0:e.message)?this.emit(t,{err:this.serializeError(e)}):this.emit(t,{err:e})}elementIdFromHref(e){return e.replace(/^[:]*:\\/\\//,\"\").replace(/[^a-z0-9]/g,\"\")}serializeError(e){const{name:t,message:n,stack:o,...i}=e;return Object.keys(i).reduce(((e,t)=>{const n=i[t];return n instanceof HTMLElement||(e[t]=n),e}),{name:t,message:n,stack:o})}}function t(){var e,t;const n=window;if(null===(t=null===(e=null==n?void 0:n.webkit)||void 0===e?void 0:e.messageHandlers)||void 0===t?void 0:t.nsBridge)return n.webkit.messageHandlers.nsBridge}class n extends e{emitEvent(e,n){const o=t();o&&o.postMessage(JSON.stringify({eventName:e,data:n}))}}const o=\"ns-bridge-ready\",i=window;if(!i.nsWebViewBridge){i.nsWebViewBridge=new n;for(const e of[o,\"ns-brige-ready\"])\"undefined\"!=typeof CustomEvent?window.dispatchEvent(new CustomEvent(e,{detail:i.nsWebViewBridge})):window.dispatchEvent(new Event(e))}"; 3 | export const metadataViewPort: string = "!function(e){const i={initialScale:1},a=e.document;let t=a.querySelector('head meta[name=\"viewport\"]');t||(t=a.createElement(\"meta\"),t.setAttribute(\"name\",\"viewport\"),a.head.appendChild(t));let l=\"<%= VIEW_PORT %>\";l&&\"string\"!=typeof l||(l=i);const{initialScale:n=i.initialScale,width:s,height:c,userScalable:m,minimumScale:o,maximumScale:u}=l,r=[`initial-scale=${n}`];if(s&&r.push(`width=${s}`),c&&r.push(`height=${c}`),\"boolean\"==typeof m)r.push(\"user-scalable=\"+(m?\"yes\":\"no\"));else if(\"string\"==typeof m){const e=`${m}`.toLowerCase();\"yes\"===e?r.push(\"user-scalable=yes\"):\"no\"===e&&r.push(\"user-scalable=no\")}o&&r.push(`minimum-scale=${o}`),u&&r.push(`maximum-scale=${u}`),t.setAttribute(\"content\",r.join(\", \"))}(window);"; 4 | -------------------------------------------------------------------------------- /src/webview/references.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | -------------------------------------------------------------------------------- /src/webview/types/android/webviewinterface.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace com { 2 | export namespace nativescript { 3 | export namespace webviewinterface { 4 | export class WebViewBridgeInterface { 5 | public emitEvent(param0: string, param1: string): void; 6 | public emitEventToNativeScript(param0: string, param1: string): void; 7 | public constructor(); 8 | } 9 | export class WebChromeClient extends globalAndroid.webkit.WebChromeClient { 10 | public setConsoleEnabled(value: boolean); 11 | public isConsoleEnabled(): boolean; 12 | public handleConsoleMessage(message: android.webkit.ConsoleMessage): boolean; 13 | } 14 | export class WebView extends globalAndroid.webkit.WebView { 15 | public setScrollEnabled(value: boolean); 16 | public getScrollEnabled(): boolean; 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/webview/types/ios/ios.d.ts: -------------------------------------------------------------------------------- 1 | declare class CustomUrlSchemeHandler extends NSObject { 2 | static alloc(): CustomUrlSchemeHandler; // inherited from NSObject 3 | 4 | static new(): CustomUrlSchemeHandler; // inherited from NSObject 5 | 6 | checkTcpPortForListenWithPort(port: number): boolean; 7 | 8 | clearRegisteredLocalResource(): void; 9 | 10 | getRegisteredLocalResourceForKey(forKey: string): string; 11 | 12 | registerLocalResourceForKeyFilepath(forKey: string, filepath: string): void; 13 | 14 | resolveFilePath(url: NSURL): string; 15 | 16 | resolveMimeTypeFromFilepath(filepath: string): string; 17 | 18 | unregisterLocalResourceForKey(forKey: string): void; 19 | 20 | webViewStartURLSchemeTask(webView: WKWebView, urlSchemeTask: WKURLSchemeTask): void; 21 | 22 | webViewStopURLSchemeTask(webView: WKWebView, urlSchemeTask: WKURLSchemeTask): void; 23 | } 24 | -------------------------------------------------------------------------------- /src/webview/types/url.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'url' { 2 | export interface ParsedUrlQuery { 3 | [key: string]: string | string[]; 4 | } 5 | 6 | export class Url { 7 | protocol?: string | null; 8 | slashes?: boolean | null; 9 | auth?: string | null; 10 | host?: string | null; 11 | port?: string | null; 12 | hostname?: string | null; 13 | hash?: string | null; 14 | search?: string | null; 15 | query?: string | null | ParsedUrlQuery; 16 | pathname?: string | null; 17 | path?: string | null; 18 | href?: string | null; 19 | public format(): string; 20 | public resolve(relative: Url): string; 21 | public resolveObject(source: string, relative: string): Url; 22 | } 23 | 24 | export function parse(input: string): Url; 25 | export function format(url: Url): string; 26 | export function resolve(source: Url, relative: Url): string; 27 | export function resolveObject(source: string, relative: string): Url; 28 | } 29 | -------------------------------------------------------------------------------- /src/webview/vue/index.ts: -------------------------------------------------------------------------------- 1 | const Plugin = { 2 | install(Vue) { 3 | Vue.registerElement('AWebView', () => require('../').AWebView); 4 | } 5 | }; 6 | 7 | export default Plugin; 8 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require('svelte-preprocess'); 2 | // const svelteNativePreprocessor = require('svelte-native-preprocessor'); 3 | 4 | module.exports = { 5 | compilerOptions: { 6 | namespace: 'foreign' 7 | }, 8 | preprocess: [ 9 | sveltePreprocess({ 10 | typescript: { 11 | compilerOptions: { 12 | target: 'es2020' 13 | } 14 | } 15 | }) 16 | // svelteNativePreprocessor() 17 | ] 18 | }; 19 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "include": ["**/*", ".eslintrc.js", "app.webpack.config.js"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tools/tsconfig", 3 | "compilerOptions": { 4 | "paths": { 5 | "@nativescript-community/ui-webview": ["src/ui-webview"], 6 | "@nativescript-community/ui-webview/*": ["src/ui-webview/*"], 7 | "@nativescript-community/ui-webview-rtc": ["src/ui-webview-rtc"], 8 | "@nativescript-community/ui-webview-rtc/*": ["src/ui-webview-rtc/*"] 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.vue3.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "composite": true, 5 | "paths": { 6 | "nativescript-vue": ["./node_modules/nativescript-vue3"] 7 | } 8 | }, 9 | "include": [ 10 | "./demo-snippets/vue3" 11 | ] 12 | } -------------------------------------------------------------------------------- /www-src/bridge-loader.android.ts.tmpl: -------------------------------------------------------------------------------- 1 | 2 | export const webViewBridge: string = ; 3 | export const metadataViewPort: string = ; 4 | -------------------------------------------------------------------------------- /www-src/bridge-loader.ios.ts.tmpl: -------------------------------------------------------------------------------- 1 | 2 | export const webViewBridge: string = ; 3 | export const metadataViewPort: string = ; 4 | -------------------------------------------------------------------------------- /www-src/bridge.android.ts: -------------------------------------------------------------------------------- 1 | import { NSWebViewBridgeBase } from './bridge.common'; 2 | 3 | declare const androidWebViewBridge: { 4 | emitEvent(eventName: string, data: string): void; 5 | }; 6 | 7 | // Forked from nativescript-webview-interface@1.4.2 8 | class NSWebViewBridge extends NSWebViewBridgeBase { 9 | private get androidWebViewBridge() { 10 | if (typeof androidWebViewBridge !== 'undefined') { 11 | return androidWebViewBridge; 12 | } 13 | } 14 | /** 15 | * Calls native android function to emit event and payload to android 16 | */ 17 | protected emitEvent(eventName: any, data: any) { 18 | this.androidWebViewBridge.emitEvent(eventName, data); 19 | } 20 | } 21 | 22 | const nsBridgeReadyEventName = 'ns-bridge-ready'; 23 | 24 | const w = window as any; 25 | if (!w.nsWebViewBridge) { 26 | // Only create the NSWebViewBridge, if is doesn't already exist. 27 | w.nsWebViewBridge = new NSWebViewBridge(); 28 | 29 | for (const eventName of [nsBridgeReadyEventName, 'ns-brige-ready']) { 30 | if (typeof CustomEvent !== 'undefined') { 31 | window.dispatchEvent( 32 | new CustomEvent(eventName, { 33 | detail: w.nsWebViewBridge 34 | }) 35 | ); 36 | } else { 37 | window.dispatchEvent(new Event(eventName)); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /www-src/bridge.ios.ts: -------------------------------------------------------------------------------- 1 | import { NSWebViewBridgeBase } from './bridge.common'; 2 | 3 | interface WKWebViewMessageHandler { 4 | postMessage(message: string): void; 5 | } 6 | // if (!Object.keys) { 7 | // Object.keys = (function () { 8 | // 'use strict'; 9 | // const hasOwnProperty = Object.prototype.hasOwnProperty; 10 | // const hasDontEnumBug = !{ toString: null }.propertyIsEnumerable('toString'); 11 | // const dontEnums = [ 12 | // 'toString', 13 | // 'toLocaleString', 14 | // 'valueOf', 15 | // 'hasOwnProperty', 16 | // 'isPrototypeOf', 17 | // 'propertyIsEnumerable', 18 | // 'constructor', 19 | // ]; 20 | // const dontEnumsLength = dontEnums.length; 21 | 22 | // return function (obj: any) { 23 | // if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) { 24 | // throw new TypeError('Object.keys called on non-object'); 25 | // } 26 | 27 | // const result = new Array(); 28 | 29 | // for (const prop in obj) { 30 | // if (hasOwnProperty.call(obj, prop)) { 31 | // result.push(prop); 32 | // } 33 | // } 34 | 35 | // if (hasDontEnumBug) { 36 | // for (let i = 0; i < dontEnumsLength; i++) { 37 | // if (hasOwnProperty.call(obj, dontEnums[i])) { 38 | // result.push(dontEnums[i]); 39 | // } 40 | // } 41 | // } 42 | 43 | // return result; 44 | // }; 45 | // })(); 46 | // } 47 | 48 | /** 49 | * With WKWebView it's assumed the there is a WKScriptMessage named nsBridge 50 | */ 51 | function getWkWebViewMessageHandler(): WKWebViewMessageHandler | void { 52 | const w = window as any; 53 | if (!w?.webkit?.messageHandlers?.nsBridge) { 54 | console.error("Cannot get the window.webkit.messageHandlers.nsBridge - we can't communicate with native-layer"); 55 | 56 | return; 57 | } 58 | 59 | return w.webkit.messageHandlers.nsBridge; 60 | } 61 | 62 | // Forked from nativescript-webview-interface@1.4.2 63 | class NSWebViewBridge extends NSWebViewBridgeBase { 64 | protected emitEvent(eventName: string, data: any) { 65 | const messageHandler = getWkWebViewMessageHandler(); 66 | if (messageHandler) { 67 | messageHandler.postMessage( 68 | JSON.stringify({ 69 | eventName, 70 | data, 71 | }) 72 | ); 73 | 74 | return; 75 | } 76 | 77 | console.error('NSWebViewBridge only supports WKWebView'); 78 | } 79 | } 80 | 81 | const nsBridgeReadyEventName = 'ns-bridge-ready'; 82 | 83 | const w = window as any; 84 | if (!w.nsWebViewBridge) { 85 | // Only create the NSWebViewBridge, if is doesn't already exist. 86 | w.nsWebViewBridge = new NSWebViewBridge(); 87 | 88 | for (const eventName of [nsBridgeReadyEventName, 'ns-brige-ready']) { 89 | if (typeof CustomEvent !== 'undefined') { 90 | window.dispatchEvent( 91 | new CustomEvent(eventName, { 92 | detail: w.nsWebViewBridge, 93 | }) 94 | ); 95 | } else { 96 | window.dispatchEvent(new Event(eventName)); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /www-src/metadata-view-port.ts: -------------------------------------------------------------------------------- 1 | interface ViewPortProperties { 2 | width?: number | 'device-width'; 3 | height?: number | 'device-height'; 4 | initialScale?: number; 5 | maximumScale?: number; 6 | minimumScale?: number; 7 | userScalable?: boolean | 'yes' | 'no'; 8 | } 9 | 10 | (function (window) { 11 | const defaultViewPort: ViewPortProperties = { 12 | initialScale: 1.0, 13 | }; 14 | 15 | const document = window.document; 16 | let meta: HTMLMetaElement | null = document.querySelector('head meta[name="viewport"]'); 17 | if (!meta) { 18 | meta = document.createElement('meta'); 19 | meta.setAttribute('name', 'viewport'); 20 | 21 | document.head.appendChild(meta); 22 | } 23 | 24 | let viewPortValues: any = '<%= VIEW_PORT %>'; 25 | if (!viewPortValues || typeof viewPortValues === 'string') { 26 | viewPortValues = defaultViewPort; 27 | } 28 | 29 | const { 30 | initialScale = defaultViewPort.initialScale, 31 | width, 32 | height, 33 | userScalable, 34 | minimumScale, 35 | maximumScale, 36 | } = viewPortValues; 37 | 38 | const content = [`initial-scale=${initialScale}`] as string[]; 39 | 40 | if (width) { 41 | content.push(`width=${width}`); 42 | } 43 | 44 | if (height) { 45 | content.push(`height=${height}`); 46 | } 47 | 48 | if (typeof userScalable === 'boolean') { 49 | content.push(`user-scalable=${userScalable ? 'yes' : 'no'}`); 50 | } else if (typeof userScalable === 'string') { 51 | const lcUserScalable = `${userScalable}`.toLowerCase(); 52 | if (lcUserScalable === 'yes') { 53 | content.push('user-scalable=yes'); 54 | } else if (lcUserScalable === 'no') { 55 | content.push('user-scalable=no'); 56 | } else { 57 | console.error(`userScalable=${JSON.stringify(userScalable)} is an unknown value`); 58 | } 59 | } 60 | 61 | if (minimumScale) { 62 | content.push(`minimum-scale=${minimumScale}`); 63 | } 64 | 65 | if (maximumScale) { 66 | content.push(`maximum-scale=${maximumScale}`); 67 | } 68 | 69 | meta.setAttribute('content', content.join(', ')); 70 | })(window); 71 | -------------------------------------------------------------------------------- /www-src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "www-src", 3 | "dependencies": { 4 | "@rollup/plugin-commonjs": "^21.0.1", 5 | "@rollup/plugin-strip": "^2.1.0", 6 | "@rollup/plugin-typescript": "^8.3.0", 7 | "promise-polyfill": "^8.2.1", 8 | "rollup": "^2.62.0", 9 | "rollup-plugin-cleanup": "^3.2.1" 10 | } 11 | } -------------------------------------------------------------------------------- /www-src/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import strip from '@rollup/plugin-strip'; 2 | import typescript from '@rollup/plugin-typescript'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import cleanup from 'rollup-plugin-cleanup'; 5 | 6 | export default [ 7 | { 8 | input: 'bridge.android.ts', 9 | plugins: [typescript(), cleanup({ comments: 'none' }), strip({ functions: ['assert.*', 'debug', 'alert'] })], 10 | 11 | output: [ 12 | { 13 | format: 'es', 14 | file: '../build/bridge.android.js', 15 | // plugins: [terser()] 16 | } 17 | ] 18 | }, 19 | { 20 | input: 'bridge.ios.ts', 21 | plugins: [commonjs({ transformMixedEsModules: true }), typescript(), cleanup({ comments: 'none' }), strip({ functions: ['assert.*', 'debug', 'alert'] })], 22 | 23 | output: [ 24 | { 25 | format: 'cjs', 26 | esModule: false, 27 | strict: false, 28 | file: '../build/bridge.ios.js' 29 | // plugins: [terser()] 30 | } 31 | ] 32 | }, 33 | { 34 | input: 'metadata-view-port.ts', 35 | plugins: [commonjs({ transformMixedEsModules: true }), typescript(), strip({ functions: ['assert.*', 'debug', 'alert'] })], 36 | 37 | output: [ 38 | { 39 | format: 'cjs', 40 | esModule: false, 41 | strict: false, 42 | file: '../build/metadata-view-port.js' 43 | // plugins: [terser()] 44 | } 45 | ] 46 | } 47 | ]; 48 | -------------------------------------------------------------------------------- /www-src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "moduleResolution": "node", 5 | "lib": ["es5", "es6", "dom"], "target": "es2019", 6 | "sourceMap": false, 7 | "removeComments": true, 8 | "noEmitHelpers": false, 9 | "importHelpers": false, 10 | "baseUrl": ".", 11 | "esModuleInterop": true, 12 | "skipLibCheck": true, 13 | "outDir": "../build" 14 | } 15 | } 16 | --------------------------------------------------------------------------------