diff --git a/1.hello-world/14.read-video-webview/android/.gitignore b/1.hello-world/14.read-video-webview/android/.gitignore new file mode 100644 index 00000000..aa724b77 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/1.hello-world/14.read-video-webview/android/RADME.md b/1.hello-world/14.read-video-webview/android/RADME.md new file mode 100644 index 00000000..33766b62 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/RADME.md @@ -0,0 +1,5 @@ +# Hello-world for Android WebView - Dynamsoft Barcode Reader Sample + +This sample demonstrates how to use the [Dynamsoft Barcode Reader](https://www.dynamsoft.com/barcode-reader/overview/) JS Edition in Android. + +If you want to learn how to use the Android Edition SDK in javascript, you can check [Android WebView Barcode Scanning](https://github.com/Dynamsoft/barcode-reader-mobile-samples/tree/main/android/JavaScript/WebViewBarcodeScanning). diff --git a/1.hello-world/14.read-video-webview/android/app/.gitignore b/1.hello-world/14.read-video-webview/android/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/build.gradle b/1.hello-world/14.read-video-webview/android/app/build.gradle new file mode 100644 index 00000000..33d838de --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/build.gradle @@ -0,0 +1,45 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' +} + +android { + namespace 'com.dynamsoft.dbrjswebview' + compileSdk 33 + + defaultConfig { + applicationId "com.dynamsoft.dbrjswebview" + minSdk 19 + targetSdk 33 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.webkit:webkit:1.4.0' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/proguard-rules.pro b/1.hello-world/14.read-video-webview/android/app/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/AndroidManifest.xml b/1.hello-world/14.read-video-webview/android/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..f557697e --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/assets/decodeBarcodeInVideo.html b/1.hello-world/14.read-video-webview/android/app/src/main/assets/decodeBarcodeInVideo.html new file mode 100644 index 00000000..742cbf88 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/assets/decodeBarcodeInVideo.html @@ -0,0 +1,72 @@ + + + + + + + + + + Dynamsoft Barcode Reader Sample - Hello World (Decoding via Camera) + + + +Loading... + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/java/com/dynamsoft/dbrjswebview/MainActivity.kt b/1.hello-world/14.read-video-webview/android/app/src/main/java/com/dynamsoft/dbrjswebview/MainActivity.kt new file mode 100644 index 00000000..8ecaf703 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/java/com/dynamsoft/dbrjswebview/MainActivity.kt @@ -0,0 +1,105 @@ +package com.dynamsoft.dbrjswebview + +import android.Manifest +import android.annotation.SuppressLint +import android.content.pm.PackageManager +import android.net.Uri +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.webkit.* +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat +import androidx.webkit.WebViewAssetLoader +import androidx.webkit.WebViewClientCompat + +class MainActivity : AppCompatActivity() { + @SuppressLint("SetJavaScriptEnabled") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + val myWebView: WebView = findViewById(R.id.webview) + myWebView.settings.javaScriptEnabled = true + myWebView.settings.mediaPlaybackRequiresUserGesture = false + myWebView.settings.domStorageEnabled = true + + myWebView.webViewClient = MyWebViewClient() + myWebView.webChromeClient = MyWebChromeClient() + + myWebView.loadUrl("https://appassets.androidplatform.net/assets/decodeBarcodeInVideo.html") + } + + // Warning: If you use online url, you don't need `LocalContentWebViewClient` + // Refer: https://developer.android.com/develop/ui/views/layout/webapps/load-local-content?hl=en + private inner class MyWebViewClient : WebViewClientCompat() { + + private val assetLoader = WebViewAssetLoader.Builder() + .addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(this@MainActivity)) + .build() + + @RequiresApi(21) + override fun shouldInterceptRequest( + view: WebView, + request: WebResourceRequest + ): WebResourceResponse? { + return assetLoader.shouldInterceptRequest(request.url) + } + + // to support API < 21 + @Deprecated("Deprecated in Java") + override fun shouldInterceptRequest( + view: WebView, + url: String + ): WebResourceResponse? { + return assetLoader.shouldInterceptRequest(Uri.parse(url)) + } + } + + var cameraPermissionReq: PermissionRequest? = null + private inner class MyWebChromeClient : WebChromeClient() { + @RequiresApi(21) + override fun onPermissionRequest(request: PermissionRequest) { + if(request.resources.contains(PermissionRequest.RESOURCE_VIDEO_CAPTURE)){ + // Refer: https://developer.android.com/training/permissions/requesting + if(ContextCompat.checkSelfPermission( + this@MainActivity, + Manifest.permission.CAMERA + ) == PackageManager.PERMISSION_GRANTED){ + // You can use the API that requires the permission. + request.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) + }else{ + // You can directly ask for the permission. + // The registered ActivityResultCallback gets the result of this request. + this@MainActivity.cameraPermissionReq = request + requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA) + } + }else{ + request.deny() + } + } + } + + // Refer: https://developer.android.com/training/permissions/requesting + @RequiresApi(21) + val requestCameraPermissionLauncher = registerForActivityResult( + ActivityResultContracts.RequestPermission() + ) { isGranted: Boolean -> + // Refer: https://www.dynamsoft.com/codepool/use-barcode-scanner-in-android-webview.html#set-up-webview + this@MainActivity.runOnUiThread { + if (isGranted) { + // Permission is granted. Continue the action or workflow in your + // app. + cameraPermissionReq?.grant(arrayOf(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) + } else { + // Explain to the user that the feature is unavailable because the + // feature requires a permission that the user has denied. At the + // same time, respect the user's decision. Don't link to system + // settings in an effort to convince the user to change their + // decision. + cameraPermissionReq?.deny() + } + cameraPermissionReq = null + } + } +} \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..2b068d11 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable/ic_launcher_background.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..07d5da9c --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/layout/activity_main.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..7b58479b --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml new file mode 100644 index 00000000..6f3b755b --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 00000000..c209e78e Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 00000000..b2dfe3d1 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 00000000..4f0f1d64 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 00000000..62b611da Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 00000000..948a3070 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..1b9a6956 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 00000000..28d4b77f Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..9287f508 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 00000000..aa7d6427 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 00000000..9126ae37 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/values-night/themes.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/values-night/themes.xml new file mode 100644 index 00000000..77300351 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/values/colors.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/colors.xml new file mode 100644 index 00000000..f8c6127d --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/values/strings.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/strings.xml new file mode 100644 index 00000000..5d77158e --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Dynamsoft Barcode + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/values/themes.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/themes.xml new file mode 100644 index 00000000..e2ed77aa --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/values/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/backup_rules.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/backup_rules.xml new file mode 100644 index 00000000..fa0f996d --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/backup_rules.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/data_extraction_rules.xml b/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 00000000..9ee9997b --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/app/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/build.gradle b/1.hello-world/14.read-video-webview/android/build.gradle new file mode 100644 index 00000000..ab2b874f --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/build.gradle @@ -0,0 +1,6 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +plugins { + id 'com.android.application' version '7.4.2' apply false + id 'com.android.library' version '7.4.2' apply false + id 'org.jetbrains.kotlin.android' version '1.8.0' apply false +} \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/gradle.properties b/1.hello-world/14.read-video-webview/android/gradle.properties new file mode 100644 index 00000000..3c5031eb --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/gradle.properties @@ -0,0 +1,23 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.jar b/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e708b1c0 Binary files /dev/null and b/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.properties b/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..dea1f353 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Apr 13 17:46:19 CST 2023 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/1.hello-world/14.read-video-webview/android/gradlew b/1.hello-world/14.read-video-webview/android/gradlew new file mode 100644 index 00000000..4f906e0c --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/1.hello-world/14.read-video-webview/android/gradlew.bat b/1.hello-world/14.read-video-webview/android/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.hello-world/14.read-video-webview/android/settings.gradle b/1.hello-world/14.read-video-webview/android/settings.gradle new file mode 100644 index 00000000..e5f9d85d --- /dev/null +++ b/1.hello-world/14.read-video-webview/android/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} +rootProject.name = "Dynamsoft Barcode" +include ':app' diff --git a/1.hello-world/14.read-video-webview/ios/.gitignore b/1.hello-world/14.read-video-webview/ios/.gitignore new file mode 100644 index 00000000..ba1ff083 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/.gitignore @@ -0,0 +1,90 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ \ No newline at end of file diff --git a/1.hello-world/14.read-video-webview/ios/README.md b/1.hello-world/14.read-video-webview/ios/README.md new file mode 100644 index 00000000..899d53d7 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/README.md @@ -0,0 +1,5 @@ +# Hello-world for iOS WKWebView - Dynamsoft Barcode Reader Sample + +This sample demonstrates how to use the [Dynamsoft Barcode Reader](https://www.dynamsoft.com/barcode-reader/overview/) JS Edition in iOS(Swift). + +If you want to learn how to use the Android Edition SDK in javascript, you can check [iOS WebView Barcode Scanning](https://github.com/Dynamsoft/barcode-reader-mobile-samples/tree/main/ios/JavaScript/WebViewBarcodeScanning). diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.pbxproj b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.pbxproj new file mode 100644 index 00000000..7f7ce301 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.pbxproj @@ -0,0 +1,373 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 68309E9F29F28D950016A358 /* html in Resources */ = {isa = PBXBuildFile; fileRef = 68309E9E29F28D950016A358 /* html */; }; + 68A0A94529EE855E00DC7D57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68A0A94429EE855E00DC7D57 /* AppDelegate.swift */; }; + 68A0A94729EE855E00DC7D57 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68A0A94629EE855E00DC7D57 /* SceneDelegate.swift */; }; + 68A0A94929EE855E00DC7D57 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68A0A94829EE855E00DC7D57 /* ViewController.swift */; }; + 68A0A94C29EE855E00DC7D57 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68A0A94A29EE855E00DC7D57 /* Main.storyboard */; }; + 68A0A94E29EE856100DC7D57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 68A0A94D29EE856100DC7D57 /* Assets.xcassets */; }; + 68A0A95129EE856100DC7D57 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68A0A94F29EE856100DC7D57 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 68309E9E29F28D950016A358 /* html */ = {isa = PBXFileReference; lastKnownFileType = folder; path = html; sourceTree = ""; }; + 68A0A94129EE855E00DC7D57 /* dbrjswebview.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dbrjswebview.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 68A0A94429EE855E00DC7D57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 68A0A94629EE855E00DC7D57 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 68A0A94829EE855E00DC7D57 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 68A0A94B29EE855E00DC7D57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 68A0A94D29EE856100DC7D57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 68A0A95029EE856100DC7D57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 68A0A95229EE856100DC7D57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 68A0A93E29EE855E00DC7D57 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 68A0A93829EE855E00DC7D57 = { + isa = PBXGroup; + children = ( + 68A0A94329EE855E00DC7D57 /* dbrjswebview */, + 68A0A94229EE855E00DC7D57 /* Products */, + ); + sourceTree = ""; + }; + 68A0A94229EE855E00DC7D57 /* Products */ = { + isa = PBXGroup; + children = ( + 68A0A94129EE855E00DC7D57 /* dbrjswebview.app */, + ); + name = Products; + sourceTree = ""; + }; + 68A0A94329EE855E00DC7D57 /* dbrjswebview */ = { + isa = PBXGroup; + children = ( + 68309E9E29F28D950016A358 /* html */, + 68A0A94429EE855E00DC7D57 /* AppDelegate.swift */, + 68A0A94629EE855E00DC7D57 /* SceneDelegate.swift */, + 68A0A94829EE855E00DC7D57 /* ViewController.swift */, + 68A0A94A29EE855E00DC7D57 /* Main.storyboard */, + 68A0A94D29EE856100DC7D57 /* Assets.xcassets */, + 68A0A94F29EE856100DC7D57 /* LaunchScreen.storyboard */, + 68A0A95229EE856100DC7D57 /* Info.plist */, + ); + path = dbrjswebview; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 68A0A94029EE855E00DC7D57 /* dbrjswebview */ = { + isa = PBXNativeTarget; + buildConfigurationList = 68A0A95529EE856100DC7D57 /* Build configuration list for PBXNativeTarget "dbrjswebview" */; + buildPhases = ( + 68A0A93D29EE855E00DC7D57 /* Sources */, + 68A0A93E29EE855E00DC7D57 /* Frameworks */, + 68A0A93F29EE855E00DC7D57 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dbrjswebview; + productName = dbrjswebview; + productReference = 68A0A94129EE855E00DC7D57 /* dbrjswebview.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 68A0A93929EE855E00DC7D57 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1400; + LastUpgradeCheck = 1400; + TargetAttributes = { + 68A0A94029EE855E00DC7D57 = { + CreatedOnToolsVersion = 14.0.1; + }; + }; + }; + buildConfigurationList = 68A0A93C29EE855E00DC7D57 /* Build configuration list for PBXProject "dbrjswebview" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 68A0A93829EE855E00DC7D57; + productRefGroup = 68A0A94229EE855E00DC7D57 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 68A0A94029EE855E00DC7D57 /* dbrjswebview */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 68A0A93F29EE855E00DC7D57 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 68A0A95129EE856100DC7D57 /* LaunchScreen.storyboard in Resources */, + 68309E9F29F28D950016A358 /* html in Resources */, + 68A0A94E29EE856100DC7D57 /* Assets.xcassets in Resources */, + 68A0A94C29EE855E00DC7D57 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 68A0A93D29EE855E00DC7D57 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 68A0A94929EE855E00DC7D57 /* ViewController.swift in Sources */, + 68A0A94529EE855E00DC7D57 /* AppDelegate.swift in Sources */, + 68A0A94729EE855E00DC7D57 /* SceneDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 68A0A94A29EE855E00DC7D57 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 68A0A94B29EE855E00DC7D57 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 68A0A94F29EE856100DC7D57 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 68A0A95029EE856100DC7D57 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 68A0A95329EE856100DC7D57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 68A0A95429EE856100DC7D57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 68A0A95629EE856100DC7D57 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = KK22Q4GV82; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = dbrjswebview/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = DyBarcode; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UIStatusBarStyle = ""; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.dynamsoft.dbrjswebview; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 68A0A95729EE856100DC7D57 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = KK22Q4GV82; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = dbrjswebview/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = DyBarcode; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UIStatusBarStyle = ""; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 14.3; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.dynamsoft.dbrjswebview; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 68A0A93C29EE855E00DC7D57 /* Build configuration list for PBXProject "dbrjswebview" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 68A0A95329EE856100DC7D57 /* Debug */, + 68A0A95429EE856100DC7D57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 68A0A95529EE856100DC7D57 /* Build configuration list for PBXNativeTarget "dbrjswebview" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 68A0A95629EE856100DC7D57 /* Debug */, + 68A0A95729EE856100DC7D57 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 68A0A93929EE855E00DC7D57 /* Project object */; +} diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/AppDelegate.swift b/1.hello-world/14.read-video-webview/ios/dbrjswebview/AppDelegate.swift new file mode 100644 index 00000000..ad05d455 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// dbrjswebview +// +// Created by Dynamsoft on 2023/4/18. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AccentColor.colorset/Contents.json b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 00000000..eb878970 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AppIcon.appiconset/Contents.json b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..13613e3e --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/Contents.json b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/Contents.json new file mode 100644 index 00000000..73c00596 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/LaunchScreen.storyboard b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000..865e9329 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/Main.storyboard b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/Main.storyboard new file mode 100644 index 00000000..85dc8abf --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Base.lproj/Main.storyboard @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/Info.plist b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Info.plist new file mode 100644 index 00000000..93bb4788 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/Info.plist @@ -0,0 +1,27 @@ + + + + + NSCameraUsageDescription + Decoding barcodes from video needs to access your camera. + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/SceneDelegate.swift b/1.hello-world/14.read-video-webview/ios/dbrjswebview/SceneDelegate.swift new file mode 100644 index 00000000..0860c7e6 --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/SceneDelegate.swift @@ -0,0 +1,52 @@ +// +// SceneDelegate.swift +// dbrjswebview +// +// Created by Dynamsoft on 2023/4/18. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/ViewController.swift b/1.hello-world/14.read-video-webview/ios/dbrjswebview/ViewController.swift new file mode 100644 index 00000000..183e95bc --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/ViewController.swift @@ -0,0 +1,106 @@ +// +// ViewController.swift +// dbrjswebview +// +// Created by Dynamsoft on 2023/4/18. +// + +import UIKit +import WebKit + +// Refer: https://developer.apple.com/documentation/webkit/viewing_desktop_or_mobile_web_content_using_a_web_view +class ViewController: UIViewController, WKUIDelegate { + + let webView: WKWebView + + required init?(coder: NSCoder) { + print("entered init") + let configuration = WKWebViewConfiguration() + configuration.allowsInlineMediaPlayback = true + configuration.mediaTypesRequiringUserActionForPlayback = [] + // Refer: https://stackoverflow.com/a/51736967 + configuration.websiteDataStore = WKWebsiteDataStore.default() + webView = WKWebView(frame: .init(), configuration: configuration) + + super.init(coder: coder) + } + + // Refer: https://www.hackingwithswift.com/articles/112/the-ultimate-guide-to-wkwebview + override func loadView() { + self.view = webView + } + + override func viewDidLoad() { + super.viewDidLoad() + print("entered viewDidLoad") + // Do any additional setup after loading the view. + + // Refer: https://stackoverflow.com/a/40316507 + webView.uiDelegate = self + + //let url = URL(string: "https://your.online.website/target/page.html")! + //webView.load(URLRequest(url: url)) + + // load local html + let fileUrl = Bundle.main.url(forResource: "html/decodeFileInVideo", withExtension: "html")! + webView.loadFileURL(fileUrl, allowingReadAccessTo: fileUrl) + print("finish viewDidLoad") + } + + // Refer: https://stackoverflow.com/a/40316507 + + func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping () -> Void) { + + let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet) + alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in + completionHandler() + })) + + present(alertController, animated: true, completion: nil) + } + + + func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping (Bool) -> Void) { + + let alertController = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet) + + alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in + completionHandler(true) + })) + + alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in + completionHandler(false) + })) + + present(alertController, animated: true, completion: nil) + } + + + func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, + completionHandler: @escaping (String?) -> Void) { + + let alertController = UIAlertController(title: nil, message: prompt, preferredStyle: .actionSheet) + + alertController.addTextField { (textField) in + textField.text = defaultText + } + + alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: { (action) in + if let text = alertController.textFields?.first?.text { + completionHandler(text) + } else { + completionHandler(defaultText) + } + })) + + alertController.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { (action) in + completionHandler(nil) + })) + + present(alertController, animated: true, completion: nil) + } + +} + diff --git a/1.hello-world/14.read-video-webview/ios/dbrjswebview/html/decodeFileInVideo.html b/1.hello-world/14.read-video-webview/ios/dbrjswebview/html/decodeFileInVideo.html new file mode 100644 index 00000000..4d2f6d5c --- /dev/null +++ b/1.hello-world/14.read-video-webview/ios/dbrjswebview/html/decodeFileInVideo.html @@ -0,0 +1,71 @@ + + + + + + + + + + Dynamsoft Barcode Reader Sample - Hello World (Decoding via Camera) + + + +Loading... + + + + + diff --git a/1.hello-world/README.md b/1.hello-world/README.md index c4b0ce55..6a5aa033 100644 --- a/1.hello-world/README.md +++ b/1.hello-world/README.md @@ -92,6 +92,10 @@ Let's quickly break down the methods used in order: Actually, it is not necessary to define both onFrameRead and onUniqueRead in the code. onUniqueRead is more commonly used because it is triggered only when a new barcode is detected, rather than on every frame. +## Hello World with WebView + +Read more in the README under "14.read-video-webview". + ## Support If you have any questions, feel free to contact Dynamsoft support via [email](mailto:support@dynamsoft.com) or [live chat](https://www.dynamsoft.com/barcode-reader/sdk-javascript/) via the "Let's Chat" button. diff --git a/README.md b/README.md index b9b703d2..c419212b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Get the basic features of the library working with plain/native JavaScript or wi * [**Hello World in Electron**](https://www.dynamsoft.com/barcode-reader/programming/javascript/samples-demos/helloworld-electron.html?utm_source=sampleReadme): Decode video stream in a Electron application from a webcam or a built-in camera**Hello World in PWA**](https://demo.dynamsoft.com/samples/dbr/js/1.hello-world/10.read-video-pwa/helloworld-pwa.html?utm_source=sampleReadme): Decode video stream in a PWA application from a webcam or a built-in camera. * [**Hello World with RequireJS**](https://demo.dynamsoft.com/samples/dbr/js/1.hello-world/11.read-video-requirejs.html?utm_source=sampleReadme): Decode video stream in an application using RequireJS from a webcam or a built-in camera. * [**Hello World with ES6**](https://demo.dynamsoft.com/samples/dbr/js/1.hello-world/12.read-video-es6.html?utm_source=sampleReadme): Decode video stream in an application using ES6 from a webcam or a built-in camera. - +* [**Hello World in WebView**](https://github.com/Dynamsoft/barcode-reader-javascript-samples/tree/main/1.hello-world/14.read-video-webview): Decode video stream in an application in WebView from camera. ### Customize Camera UI * [**Use the Default Camera UI**](https://demo.dynamsoft.com/samples/dbr/js/2.ui-tweaking/1.read-video-show-result.html?utm_source=sampleReadme): Show the default camera UI to decode video stream from a webcam or a built-in camera. diff --git a/index.html b/index.html index 056729d6..0e9a8a79 100644 --- a/index.html +++ b/index.html @@ -137,6 +137,11 @@

Barcode Reader Samples

ES6 +
Customize Camera UI