50
.github/workflows/android.yml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
name: Build Android APK
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
# Se non hai un comando build, questo step viene ignorato
|
||||
- name: Build web (optional)
|
||||
if: ${{ false }}
|
||||
run: npm run build
|
||||
|
||||
- name: Install Capacitor Android + Sync
|
||||
run: |
|
||||
npm install @capacitor/android
|
||||
npx cap sync android
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
|
||||
- name: Build Android Debug APK
|
||||
run: |
|
||||
cd android
|
||||
./gradlew assembleDebug
|
||||
|
||||
- name: Upload APK
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: app-debug.apk
|
||||
path: android/app/build/outputs/apk/debug/app-debug.apk
|
||||
0
README.md
Normal file
101
android/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
|
||||
|
||||
# Built application files
|
||||
*.apk
|
||||
*.aar
|
||||
*.ap_
|
||||
*.aab
|
||||
|
||||
# Files for the ART/Dalvik VM
|
||||
*.dex
|
||||
|
||||
# Java class files
|
||||
*.class
|
||||
|
||||
# Generated files
|
||||
bin/
|
||||
gen/
|
||||
out/
|
||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||
# release/
|
||||
|
||||
# Gradle files
|
||||
.gradle/
|
||||
build/
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
local.properties
|
||||
|
||||
# Proguard folder generated by Eclipse
|
||||
proguard/
|
||||
|
||||
# Log Files
|
||||
*.log
|
||||
|
||||
# Android Studio Navigation editor temp files
|
||||
.navigation/
|
||||
|
||||
# Android Studio captures folder
|
||||
captures/
|
||||
|
||||
# IntelliJ
|
||||
*.iml
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/gradle.xml
|
||||
.idea/assetWizardSettings.xml
|
||||
.idea/dictionaries
|
||||
.idea/libraries
|
||||
# Android Studio 3 in .gitignore file.
|
||||
.idea/caches
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
#*.jks
|
||||
#*.keystore
|
||||
|
||||
# External native build folder generated in Android Studio 2.2 and later
|
||||
.externalNativeBuild
|
||||
.cxx/
|
||||
|
||||
# Google Services (e.g. APIs or Firebase)
|
||||
# google-services.json
|
||||
|
||||
# Freeline
|
||||
freeline.py
|
||||
freeline/
|
||||
freeline_project_description.json
|
||||
|
||||
# fastlane
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
fastlane/test_output
|
||||
fastlane/readme.md
|
||||
|
||||
# Version control
|
||||
vcs.xml
|
||||
|
||||
# lint
|
||||
lint/intermediates/
|
||||
lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
# Android Profiling
|
||||
*.hprof
|
||||
|
||||
# Cordova plugins for Capacitor
|
||||
capacitor-cordova-android-plugins
|
||||
|
||||
# Copied web assets
|
||||
app/src/main/assets/public
|
||||
|
||||
# Generated Config files
|
||||
app/src/main/assets/capacitor.config.json
|
||||
app/src/main/assets/capacitor.plugins.json
|
||||
app/src/main/res/xml/config.xml
|
||||
2
android/app/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/build/*
|
||||
!/build/.npmkeep
|
||||
54
android/app/build.gradle
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
namespace = "com.example.myapp"
|
||||
compileSdk = rootProject.ext.compileSdkVersion
|
||||
defaultConfig {
|
||||
applicationId "com.example.myapp"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
||||
ignoreAssetsPattern = '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
flatDir{
|
||||
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
||||
implementation project(':capacitor-android')
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
implementation project(':capacitor-cordova-android-plugins')
|
||||
}
|
||||
|
||||
apply from: 'capacitor.build.gradle'
|
||||
|
||||
try {
|
||||
def servicesJSON = file('google-services.json')
|
||||
if (servicesJSON.text) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
}
|
||||
} catch(Exception e) {
|
||||
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
||||
}
|
||||
19
android/app/capacitor.build.gradle
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
|
||||
android {
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||
dependencies {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (hasProperty('postBuildExtras')) {
|
||||
postBuildExtras()
|
||||
}
|
||||
21
android/app/proguard-rules.pro
vendored
Normal file
|
|
@ -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
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.getcapacitor.myapp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
|
||||
@Test
|
||||
public void useAppContext() throws Exception {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
assertEquals("com.getcapacitor.app", appContext.getPackageName());
|
||||
}
|
||||
}
|
||||
41
android/app/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation|density"
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/title_activity_main"
|
||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||
android:launchMode="singleTask"
|
||||
android:exported="true">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths"></meta-data>
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<!-- Permissions -->
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package com.example.myapp;
|
||||
|
||||
import com.getcapacitor.BridgeActivity;
|
||||
|
||||
public class MainActivity extends BridgeActivity {}
|
||||
BIN
android/app/src/main/res/drawable-land-hdpi/splash.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
android/app/src/main/res/drawable-land-mdpi/splash.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
android/app/src/main/res/drawable-land-xhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 9 KiB |
BIN
android/app/src/main/res/drawable-land-xxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
android/app/src/main/res/drawable-land-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
android/app/src/main/res/drawable-port-hdpi/splash.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
android/app/src/main/res/drawable-port-mdpi/splash.png
Normal file
|
After Width: | Height: | Size: 4 KiB |
BIN
android/app/src/main/res/drawable-port-xhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
android/app/src/main/res/drawable-port-xxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
android/app/src/main/res/drawable-port-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -0,0 +1,34 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
</vector>
|
||||
170
android/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
<path
|
||||
android:fillColor="#26A69A"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF"
|
||||
android:strokeWidth="0.8" />
|
||||
</vector>
|
||||
BIN
android/app/src/main/res/drawable/splash.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
12
android/app/src/main/res/layout/activity_main.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
</resources>
|
||||
7
android/app/src/main/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<resources>
|
||||
<string name="app_name">myapp</string>
|
||||
<string name="title_activity_main">myapp</string>
|
||||
<string name="package_name">com.example.myapp</string>
|
||||
<string name="custom_url_scheme">com.example.myapp</string>
|
||||
</resources>
|
||||
22
android/app/src/main/res/values/styles.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||
<item name="android:background">@drawable/splash</item>
|
||||
</style>
|
||||
</resources>
|
||||
5
android/app/src/main/res/xml/file_paths.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="my_images" path="." />
|
||||
<cache-path name="my_cache_images" path="." />
|
||||
</paths>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.getcapacitor.myapp;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
29
android/build.gradle
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
classpath 'com.google.gms:google-services:4.4.4'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "variables.gradle"
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
3
android/capacitor.settings.gradle
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||
include ':capacitor-android'
|
||||
project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor')
|
||||
22
android/gradle.properties
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# 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=-Xmx1536m
|
||||
|
||||
# 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
|
||||
BIN
android/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
251
android/gradlew
vendored
Executable file
|
|
@ -0,0 +1,251 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original 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.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# 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 ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# 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
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
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
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
94
android/gradlew.bat
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
@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
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@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=.
|
||||
@rem This is normally unused
|
||||
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% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 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!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
5
android/settings.gradle
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
include ':app'
|
||||
include ':capacitor-cordova-android-plugins'
|
||||
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
|
||||
|
||||
apply from: 'capacitor.settings.gradle'
|
||||
16
android/variables.gradle
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
ext {
|
||||
minSdkVersion = 24
|
||||
compileSdkVersion = 36
|
||||
targetSdkVersion = 36
|
||||
androidxActivityVersion = '1.11.0'
|
||||
androidxAppCompatVersion = '1.7.1'
|
||||
androidxCoordinatorLayoutVersion = '1.3.0'
|
||||
androidxCoreVersion = '1.17.0'
|
||||
androidxFragmentVersion = '1.8.9'
|
||||
coreSplashScreenVersion = '1.2.0'
|
||||
androidxWebkitVersion = '1.14.0'
|
||||
junitVersion = '4.13.2'
|
||||
androidxJunitVersion = '1.3.0'
|
||||
androidxEspressoCoreVersion = '3.7.0'
|
||||
cordovaAndroidVersion = '14.0.1'
|
||||
}
|
||||
7
capacitor.config.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
{
|
||||
"appId": "it.patachina.myapps",
|
||||
"appName": "myapps",
|
||||
"webDir": "www",
|
||||
"bundledWebRuntime": false
|
||||
}
|
||||
1
node_modules/.bin/cap
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../@capacitor/cli/bin/capacitor
|
||||
1
node_modules/.bin/capacitor
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../@capacitor/cli/bin/capacitor
|
||||
1
node_modules/.bin/is-docker
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../is-docker/cli.js
|
||||
1
node_modules/.bin/mkdirp
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../mkdirp/bin/cmd.js
|
||||
1
node_modules/.bin/native-run
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../native-run/bin/native-run
|
||||
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../which/bin/node-which
|
||||
1
node_modules/.bin/rimraf
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../rimraf/dist/esm/bin.mjs
|
||||
1
node_modules/.bin/semver
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../semver/bin/semver.js
|
||||
1
node_modules/.bin/tree-kill
generated
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../tree-kill/cli.js
|
||||
1110
node_modules/.package-lock.json
generated
vendored
Normal file
21
node_modules/@capacitor/android/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017-present Drifty Co.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
94
node_modules/@capacitor/android/capacitor/build.gradle
generated
vendored
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
ext {
|
||||
androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.11.0'
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
||||
androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.3.0'
|
||||
androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.17.0'
|
||||
androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.8.9'
|
||||
androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.14.0'
|
||||
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
||||
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
||||
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
||||
cordovaAndroidVersion = project.hasProperty('cordovaAndroidVersion') ? rootProject.ext.cordovaAndroidVersion : '14.0.1'
|
||||
}
|
||||
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.13.0'
|
||||
|
||||
if (System.getenv("CAP_PUBLISH") == "true") {
|
||||
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc).all { enabled = false }
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
if (System.getenv("CAP_PUBLISH") == "true") {
|
||||
apply plugin: 'io.github.gradle-nexus.publish-plugin'
|
||||
apply from: file('../scripts/publish-root.gradle')
|
||||
apply from: file('../scripts/publish-module.gradle')
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.getcapacitor.android"
|
||||
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
||||
defaultConfig {
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
consumerProguardFiles 'proguard-rules.pro'
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
baseline file("lint-baseline.xml")
|
||||
abortOnError = true
|
||||
warningsAsErrors = true
|
||||
lintConfig = file('lint.xml')
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
publishing {
|
||||
singleVariant("release")
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
implementation "androidx.core:core:$androidxCoreVersion"
|
||||
implementation "androidx.activity:activity:$androidxActivityVersion"
|
||||
implementation "androidx.fragment:fragment:$androidxFragmentVersion"
|
||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||
implementation "androidx.webkit:webkit:$androidxWebkitVersion"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
implementation "org.apache.cordova:framework:$cordovaAndroidVersion"
|
||||
testImplementation 'org.json:json:20250517'
|
||||
testImplementation 'org.mockito:mockito-core:5.20.0'
|
||||
}
|
||||
|
||||
136
node_modules/@capacitor/android/capacitor/lint-baseline.xml
generated
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<issues format="5" by="lint 4.1.1" client="gradle" variant="all" version="4.1.1">
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `String.format(Locale, ...)` instead"
|
||||
errorLine1=" String msg = String.format("
|
||||
errorLine2=" ^">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeWebChromeClient.java"
|
||||
line="474"
|
||||
column="26"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" return mask.toUpperCase().equals(string.toUpperCase());"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/util/HostMask.java"
|
||||
line="110"
|
||||
column="29"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toUpperCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" return mask.toUpperCase().equals(string.toUpperCase());"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/util/HostMask.java"
|
||||
line="110"
|
||||
column="57"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" switch (spinnerStyle.toLowerCase()) {"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/Splash.java"
|
||||
line="127"
|
||||
column="38"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="DefaultLocale"
|
||||
message="Implicitly using the default locale is a common source of bugs: Use `toLowerCase(Locale)` instead. For strings meant to be internal use `Locale.ROOT`, otherwise `Locale.getDefault()`."
|
||||
errorLine1=" if (header.getKey().equalsIgnoreCase("Accept") && header.getValue().toLowerCase().contains("text/html")) {"
|
||||
errorLine2=" ~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/WebViewLocalServer.java"
|
||||
line="327"
|
||||
column="89"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SimpleDateFormat"
|
||||
message="To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, or `getTimeInstance()`, or use `new SimpleDateFormat(String template, Locale locale)` with for example `Locale.US` for ASCII dates."
|
||||
errorLine1=" String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeWebChromeClient.java"
|
||||
line="511"
|
||||
column="28"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SimpleDateFormat"
|
||||
message="To get local formatting use `getDateInstance()`, `getDateTimeInstance()`, or `getTimeInstance()`, or use `new SimpleDateFormat(String template, Locale locale)` with for example `Locale.US` for ASCII dates."
|
||||
errorLine1=" DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/PluginResult.java"
|
||||
line="44"
|
||||
column="25"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="SetJavaScriptEnabled"
|
||||
message="Using `setJavaScriptEnabled` can introduce XSS vulnerabilities into your application, review carefully"
|
||||
errorLine1=" settings.setJavaScriptEnabled(true);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/Bridge.java"
|
||||
line="384"
|
||||
column="9"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Recycle"
|
||||
message="This `TypedArray` should be recycled after use with `#recycle()`"
|
||||
errorLine1=" TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.bridge_fragment);"
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/BridgeFragment.java"
|
||||
line="84"
|
||||
column="32"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="StaticFieldLeak"
|
||||
message="Do not place Android context classes in static fields; this is a memory leak"
|
||||
errorLine1=" private static ImageView splashImage;"
|
||||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/Splash.java"
|
||||
line="41"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="StaticFieldLeak"
|
||||
message="Do not place Android context classes in static fields; this is a memory leak"
|
||||
errorLine1=" private static ProgressBar spinnerBar;"
|
||||
errorLine2=" ~~~~~~">
|
||||
<location
|
||||
file="src/main/java/com/getcapacitor/Splash.java"
|
||||
line="42"
|
||||
column="13"/>
|
||||
</issue>
|
||||
|
||||
<issue
|
||||
id="Overdraw"
|
||||
message="Possible overdraw: Root element paints background `#F0FF1414` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)"
|
||||
errorLine1=" android:background="#F0FF1414""
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="src/main/res/layout/fragment_bridge.xml"
|
||||
line="5"
|
||||
column="5"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
9
node_modules/@capacitor/android/capacitor/lint.xml
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<issue id="GradleDependency" severity="ignore" />
|
||||
<issue id="AndroidGradlePluginVersion" severity="ignore" />
|
||||
<issue id="DiscouragedApi">
|
||||
<ignore path="src/main/java/com/getcapacitor/plugin/util/AssetUtil.java" />
|
||||
</issue>
|
||||
<issue id="ObsoleteSdkInt" severity="informational" />
|
||||
</lint>
|
||||
28
node_modules/@capacitor/android/capacitor/proguard-rules.pro
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# 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
|
||||
|
||||
# Rules for Capacitor v3 plugins and annotations
|
||||
-keep @com.getcapacitor.annotation.CapacitorPlugin public class * {
|
||||
@com.getcapacitor.annotation.PermissionCallback <methods>;
|
||||
@com.getcapacitor.annotation.ActivityCallback <methods>;
|
||||
@com.getcapacitor.annotation.Permission <methods>;
|
||||
@com.getcapacitor.PluginMethod public <methods>;
|
||||
}
|
||||
|
||||
-keep public class * extends com.getcapacitor.Plugin { *; }
|
||||
|
||||
# Rules for Capacitor v2 plugins and annotations
|
||||
# These are deprecated but can still be used with Capacitor for now
|
||||
-keep @com.getcapacitor.NativePlugin public class * {
|
||||
@com.getcapacitor.PluginMethod public <methods>;
|
||||
}
|
||||
|
||||
# Rules for Cordova plugins
|
||||
-keep public class * extends org.apache.cordova.* {
|
||||
public <methods>;
|
||||
public <fields>;
|
||||
}
|
||||
3
node_modules/@capacitor/android/capacitor/src/main/AndroidManifest.xml
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
</manifest>
|
||||
1035
node_modules/@capacitor/android/capacitor/src/main/assets/native-bridge.js
generated
vendored
Normal file
94
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AndroidProtocolHandler.java
generated
vendored
Executable file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package com.getcapacitor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.net.Uri;
|
||||
import android.util.TypedValue;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
public class AndroidProtocolHandler {
|
||||
|
||||
private Context context;
|
||||
|
||||
public AndroidProtocolHandler(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public InputStream openAsset(String path) throws IOException {
|
||||
return context.getAssets().open(path, AssetManager.ACCESS_STREAMING);
|
||||
}
|
||||
|
||||
public InputStream openResource(Uri uri) {
|
||||
assert uri.getPath() != null;
|
||||
// The path must be of the form ".../asset_type/asset_name.ext".
|
||||
List<String> pathSegments = uri.getPathSegments();
|
||||
String assetType = pathSegments.get(pathSegments.size() - 2);
|
||||
String assetName = pathSegments.get(pathSegments.size() - 1);
|
||||
|
||||
// Drop the file extension.
|
||||
assetName = assetName.split("\\.")[0];
|
||||
try {
|
||||
// Use the application context for resolving the resource package name so that we do
|
||||
// not use the browser's own resources. Note that if 'context' here belongs to the
|
||||
// test suite, it does not have a separate application context. In that case we use
|
||||
// the original context object directly.
|
||||
if (context.getApplicationContext() != null) {
|
||||
context = context.getApplicationContext();
|
||||
}
|
||||
int fieldId = getFieldId(context, assetType, assetName);
|
||||
int valueType = getValueType(context, fieldId);
|
||||
if (valueType == TypedValue.TYPE_STRING) {
|
||||
return context.getResources().openRawResource(fieldId);
|
||||
} else {
|
||||
Logger.error("Asset not of type string: " + uri);
|
||||
}
|
||||
} catch (ClassNotFoundException | IllegalAccessException | NoSuchFieldException e) {
|
||||
Logger.error("Unable to open resource URL: " + uri, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int getFieldId(Context context, String assetType, String assetName)
|
||||
throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
|
||||
Class<?> d = context.getClassLoader().loadClass(context.getPackageName() + ".R$" + assetType);
|
||||
java.lang.reflect.Field field = d.getField(assetName);
|
||||
return field.getInt(null);
|
||||
}
|
||||
|
||||
public InputStream openFile(String filePath) throws IOException {
|
||||
String realPath = filePath.replace(Bridge.CAPACITOR_FILE_START, "");
|
||||
File localFile = new File(realPath);
|
||||
return new FileInputStream(localFile);
|
||||
}
|
||||
|
||||
public InputStream openContentUrl(Uri uri) throws IOException {
|
||||
Integer port = uri.getPort();
|
||||
String baseUrl = uri.getScheme() + "://" + uri.getHost();
|
||||
if (port != -1) {
|
||||
baseUrl += ":" + port;
|
||||
}
|
||||
String realPath = uri.toString().replace(baseUrl + Bridge.CAPACITOR_CONTENT_START, "content:/");
|
||||
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = context.getContentResolver().openInputStream(Uri.parse(realPath));
|
||||
} catch (SecurityException e) {
|
||||
Logger.error("Unable to open content URL: " + uri, e);
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
private static int getValueType(Context context, int fieldId) {
|
||||
TypedValue value = new TypedValue();
|
||||
context.getResources().getValue(fieldId, value, true);
|
||||
return value.type;
|
||||
}
|
||||
}
|
||||
61
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/App.java
generated
vendored
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Interface for callbacks when app status changes.
|
||||
*/
|
||||
public interface AppStatusChangeListener {
|
||||
void onAppStatusChanged(Boolean isActive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for callbacks when app is restored with pending plugin call.
|
||||
*/
|
||||
public interface AppRestoredListener {
|
||||
void onAppRestored(PluginResult result);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private AppStatusChangeListener statusChangeListener;
|
||||
|
||||
@Nullable
|
||||
private AppRestoredListener appRestoredListener;
|
||||
|
||||
private boolean isActive = false;
|
||||
|
||||
public boolean isActive() {
|
||||
return isActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object to receive callbacks.
|
||||
* @param listener
|
||||
*/
|
||||
public void setStatusChangeListener(@Nullable AppStatusChangeListener listener) {
|
||||
this.statusChangeListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object to receive callbacks.
|
||||
* @param listener
|
||||
*/
|
||||
public void setAppRestoredListener(@Nullable AppRestoredListener listener) {
|
||||
this.appRestoredListener = listener;
|
||||
}
|
||||
|
||||
protected void fireRestoredResult(PluginResult result) {
|
||||
if (appRestoredListener != null) {
|
||||
appRestoredListener.onAppRestored(result);
|
||||
}
|
||||
}
|
||||
|
||||
public void fireStatusChange(boolean isActive) {
|
||||
this.isActive = isActive;
|
||||
if (statusChangeListener != null) {
|
||||
statusChangeListener.onAppStatusChanged(isActive);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/AppUUID.java
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public final class AppUUID {
|
||||
|
||||
private static final String KEY = "CapacitorAppUUID";
|
||||
|
||||
public static String getAppUUID(AppCompatActivity activity) throws Exception {
|
||||
assertAppUUID(activity);
|
||||
return readUUID(activity);
|
||||
}
|
||||
|
||||
public static void regenerateAppUUID(AppCompatActivity activity) throws Exception {
|
||||
try {
|
||||
String uuid = generateUUID();
|
||||
writeUUID(activity, uuid);
|
||||
} catch (NoSuchAlgorithmException ex) {
|
||||
throw new Exception("Capacitor App UUID could not be generated.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertAppUUID(AppCompatActivity activity) throws Exception {
|
||||
String uuid = readUUID(activity);
|
||||
if (uuid.equals("")) {
|
||||
regenerateAppUUID(activity);
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateUUID() throws NoSuchAlgorithmException {
|
||||
MessageDigest salt = MessageDigest.getInstance("SHA-256");
|
||||
salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
|
||||
return bytesToHex(salt.digest());
|
||||
}
|
||||
|
||||
private static String readUUID(AppCompatActivity activity) {
|
||||
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
|
||||
return sharedPref.getString(KEY, "");
|
||||
}
|
||||
|
||||
private static void writeUUID(AppCompatActivity activity, String uuid) {
|
||||
SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = sharedPref.edit();
|
||||
editor.putString(KEY, uuid);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] bytes) {
|
||||
byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
|
||||
byte[] hexChars = new byte[bytes.length * 2];
|
||||
for (int j = 0; j < bytes.length; j++) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
||||
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars, StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
1627
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Bridge.java
generated
vendored
Normal file
212
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java
generated
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import com.getcapacitor.android.R;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BridgeActivity extends AppCompatActivity {
|
||||
|
||||
protected Bridge bridge;
|
||||
protected boolean keepRunning = true;
|
||||
protected CapConfig config;
|
||||
|
||||
protected int activityDepth = 0;
|
||||
protected List<Class<? extends Plugin>> initialPlugins = new ArrayList<>();
|
||||
protected final Bridge.Builder bridgeBuilder = new Bridge.Builder(this);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
bridgeBuilder.setInstanceState(savedInstanceState);
|
||||
getApplication().setTheme(R.style.AppTheme_NoActionBar);
|
||||
setTheme(R.style.AppTheme_NoActionBar);
|
||||
try {
|
||||
setContentView(R.layout.capacitor_bridge_layout_main);
|
||||
} catch (Exception ex) {
|
||||
setContentView(R.layout.no_webview);
|
||||
return;
|
||||
}
|
||||
|
||||
PluginManager loader = new PluginManager(getAssets());
|
||||
|
||||
try {
|
||||
bridgeBuilder.addPlugins(loader.loadPluginClasses());
|
||||
} catch (PluginLoadException ex) {
|
||||
Logger.error("Error loading plugins.", ex);
|
||||
}
|
||||
|
||||
this.load();
|
||||
}
|
||||
|
||||
protected void load() {
|
||||
Logger.debug("Starting BridgeActivity");
|
||||
|
||||
bridge = bridgeBuilder.addPlugins(initialPlugins).setConfig(config).create();
|
||||
|
||||
this.keepRunning = bridge.shouldKeepRunning();
|
||||
this.onNewIntent(getIntent());
|
||||
}
|
||||
|
||||
public void registerPlugin(Class<? extends Plugin> plugin) {
|
||||
bridgeBuilder.addPlugin(plugin);
|
||||
}
|
||||
|
||||
public void registerPlugins(List<Class<? extends Plugin>> plugins) {
|
||||
bridgeBuilder.addPlugins(plugins);
|
||||
}
|
||||
|
||||
public Bridge getBridge() {
|
||||
return this.bridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
bridge.saveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
activityDepth++;
|
||||
if (this.bridge != null) {
|
||||
this.bridge.onStart();
|
||||
Logger.debug("App started");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart() {
|
||||
super.onRestart();
|
||||
this.bridge.onRestart();
|
||||
Logger.debug("App restarted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (bridge != null) {
|
||||
bridge.getApp().fireStatusChange(true);
|
||||
this.bridge.onResume();
|
||||
Logger.debug("App resumed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (bridge != null) {
|
||||
this.bridge.onPause();
|
||||
Logger.debug("App paused");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
if (bridge != null) {
|
||||
activityDepth = Math.max(0, activityDepth - 1);
|
||||
if (activityDepth == 0) {
|
||||
bridge.getApp().fireStatusChange(false);
|
||||
}
|
||||
|
||||
this.bridge.onStop();
|
||||
Logger.debug("App stopped");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (this.bridge != null) {
|
||||
this.bridge.onDestroy();
|
||||
Logger.debug("App destroyed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
this.bridge.onDetachedFromWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles permission request results.
|
||||
*
|
||||
* Capacitor is backwards compatible such that plugins using legacy permission request codes
|
||||
* may coexist with plugins using the AndroidX Activity v1.2 permission callback flow introduced
|
||||
* in Capacitor 3.0.
|
||||
*
|
||||
* In this method, plugins are checked first for ownership of the legacy permission request code.
|
||||
* If the {@link Bridge#onRequestPermissionsResult(int, String[], int[])} method indicates it has
|
||||
* handled the permission, then the permission callback will be considered complete. Otherwise,
|
||||
* the permission will be handled using the AndroidX Activity flow.
|
||||
*
|
||||
* @param requestCode the request code associated with the permission request
|
||||
* @param permissions the Android permission strings requested
|
||||
* @param grantResults the status result of the permission request
|
||||
*/
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (this.bridge == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles activity results.
|
||||
*
|
||||
* Capacitor is backwards compatible such that plugins using legacy activity result codes
|
||||
* may coexist with plugins using the AndroidX Activity v1.2 activity callback flow introduced
|
||||
* in Capacitor 3.0.
|
||||
*
|
||||
* In this method, plugins are checked first for ownership of the legacy request code. If the
|
||||
* {@link Bridge#onActivityResult(int, int, Intent)} method indicates it has handled the activity
|
||||
* result, then the callback will be considered complete. Otherwise, the result will be handled
|
||||
* using the AndroidX Activiy flow.
|
||||
*
|
||||
* @param requestCode the request code associated with the activity result
|
||||
* @param resultCode the result code
|
||||
* @param data any data included with the activity result
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (this.bridge == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bridge.onActivityResult(requestCode, resultCode, data)) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
|
||||
if (this.bridge == null || intent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bridge.onNewIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
if (this.bridge == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.bridge.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
467
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java
generated
vendored
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.view.View;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.GeolocationPermissions;
|
||||
import android.webkit.JsPromptResult;
|
||||
import android.webkit.JsResult;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.webkit.PermissionRequest;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.EditText;
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.FileProvider;
|
||||
import com.getcapacitor.util.PermissionHelper;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Custom WebChromeClient handler, required for showing dialogs, confirms, etc. in our
|
||||
* WebView instance.
|
||||
*/
|
||||
public class BridgeWebChromeClient extends WebChromeClient {
|
||||
|
||||
private interface PermissionListener {
|
||||
void onPermissionSelect(Boolean isGranted);
|
||||
}
|
||||
|
||||
private interface ActivityResultListener {
|
||||
void onActivityResult(ActivityResult result);
|
||||
}
|
||||
|
||||
private ActivityResultLauncher permissionLauncher;
|
||||
private ActivityResultLauncher activityLauncher;
|
||||
private PermissionListener permissionListener;
|
||||
private ActivityResultListener activityListener;
|
||||
|
||||
private Bridge bridge;
|
||||
|
||||
public BridgeWebChromeClient(Bridge bridge) {
|
||||
this.bridge = bridge;
|
||||
|
||||
ActivityResultCallback<Map<String, Boolean>> permissionCallback = (Map<String, Boolean> isGranted) -> {
|
||||
if (permissionListener != null) {
|
||||
boolean granted = true;
|
||||
for (Map.Entry<String, Boolean> permission : isGranted.entrySet()) {
|
||||
if (!permission.getValue()) granted = false;
|
||||
}
|
||||
permissionListener.onPermissionSelect(granted);
|
||||
}
|
||||
};
|
||||
|
||||
permissionLauncher = bridge.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback);
|
||||
activityLauncher = bridge.registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> {
|
||||
if (activityListener != null) {
|
||||
activityListener.onActivityResult(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render web content in `view`.
|
||||
*
|
||||
* Both this method and {@link #onHideCustomView()} are required for
|
||||
* rendering web content in full screen.
|
||||
*
|
||||
* @see <a href="https://developer.android.com/reference/android/webkit/WebChromeClient#onShowCustomView(android.view.View,%20android.webkit.WebChromeClient.CustomViewCallback)">onShowCustomView() docs</a>
|
||||
*/
|
||||
@Override
|
||||
public void onShowCustomView(View view, CustomViewCallback callback) {
|
||||
callback.onCustomViewHidden();
|
||||
super.onShowCustomView(view, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render web content in the original Web View again.
|
||||
*
|
||||
* Do not remove this method--@see #onShowCustomView(View, CustomViewCallback).
|
||||
*/
|
||||
@Override
|
||||
public void onHideCustomView() {
|
||||
super.onHideCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPermissionRequest(final PermissionRequest request) {
|
||||
List<String> permissionList = new ArrayList<>();
|
||||
if (Arrays.asList(request.getResources()).contains("android.webkit.resource.VIDEO_CAPTURE")) {
|
||||
permissionList.add(Manifest.permission.CAMERA);
|
||||
}
|
||||
if (Arrays.asList(request.getResources()).contains("android.webkit.resource.AUDIO_CAPTURE")) {
|
||||
permissionList.add(Manifest.permission.MODIFY_AUDIO_SETTINGS);
|
||||
permissionList.add(Manifest.permission.RECORD_AUDIO);
|
||||
}
|
||||
if (!permissionList.isEmpty()) {
|
||||
String[] permissions = permissionList.toArray(new String[0]);
|
||||
permissionListener = (isGranted) -> {
|
||||
if (isGranted) {
|
||||
request.grant(request.getResources());
|
||||
} else {
|
||||
request.deny();
|
||||
}
|
||||
};
|
||||
permissionLauncher.launch(permissions);
|
||||
} else {
|
||||
request.grant(request.getResources());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the browser alert modal
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
|
||||
if (bridge.getActivity().isFinishing()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
|
||||
builder
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK", (dialog, buttonIndex) -> {
|
||||
dialog.dismiss();
|
||||
result.confirm();
|
||||
})
|
||||
.setOnCancelListener((dialog) -> {
|
||||
dialog.dismiss();
|
||||
result.cancel();
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the browser confirm modal
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
|
||||
if (bridge.getActivity().isFinishing()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
|
||||
|
||||
builder
|
||||
.setMessage(message)
|
||||
.setPositiveButton("OK", (dialog, buttonIndex) -> {
|
||||
dialog.dismiss();
|
||||
result.confirm();
|
||||
})
|
||||
.setNegativeButton("Cancel", (dialog, buttonIndex) -> {
|
||||
dialog.dismiss();
|
||||
result.cancel();
|
||||
})
|
||||
.setOnCancelListener((dialog) -> {
|
||||
dialog.dismiss();
|
||||
result.cancel();
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the browser prompt modal
|
||||
* @param view
|
||||
* @param url
|
||||
* @param message
|
||||
* @param defaultValue
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, final JsPromptResult result) {
|
||||
if (bridge.getActivity().isFinishing()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
|
||||
final EditText input = new EditText(view.getContext());
|
||||
|
||||
builder
|
||||
.setMessage(message)
|
||||
.setView(input)
|
||||
.setPositiveButton("OK", (dialog, buttonIndex) -> {
|
||||
dialog.dismiss();
|
||||
|
||||
String inputText1 = input.getText().toString().trim();
|
||||
result.confirm(inputText1);
|
||||
})
|
||||
.setNegativeButton("Cancel", (dialog, buttonIndex) -> {
|
||||
dialog.dismiss();
|
||||
result.cancel();
|
||||
})
|
||||
.setOnCancelListener((dialog) -> {
|
||||
dialog.dismiss();
|
||||
result.cancel();
|
||||
});
|
||||
|
||||
AlertDialog dialog = builder.create();
|
||||
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the browser geolocation permission prompt
|
||||
* @param origin
|
||||
* @param callback
|
||||
*/
|
||||
@Override
|
||||
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
|
||||
super.onGeolocationPermissionsShowPrompt(origin, callback);
|
||||
Logger.debug("onGeolocationPermissionsShowPrompt: DOING IT HERE FOR ORIGIN: " + origin);
|
||||
final String[] geoPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION };
|
||||
|
||||
if (!PermissionHelper.hasPermissions(bridge.getContext(), geoPermissions)) {
|
||||
permissionListener = (isGranted) -> {
|
||||
if (isGranted) {
|
||||
callback.invoke(origin, true, false);
|
||||
} else {
|
||||
final String[] coarsePermission = { Manifest.permission.ACCESS_COARSE_LOCATION };
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||
PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission)
|
||||
) {
|
||||
callback.invoke(origin, true, false);
|
||||
} else {
|
||||
callback.invoke(origin, false, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
permissionLauncher.launch(geoPermissions);
|
||||
} else {
|
||||
// permission is already granted
|
||||
callback.invoke(origin, true, false);
|
||||
Logger.debug("onGeolocationPermissionsShowPrompt: has required permission");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShowFileChooser(
|
||||
WebView webView,
|
||||
final ValueCallback<Uri[]> filePathCallback,
|
||||
final FileChooserParams fileChooserParams
|
||||
) {
|
||||
List<String> acceptTypes = Arrays.asList(fileChooserParams.getAcceptTypes());
|
||||
boolean captureEnabled = fileChooserParams.isCaptureEnabled();
|
||||
boolean capturePhoto = captureEnabled && acceptTypes.contains("image/*");
|
||||
final boolean captureVideo = captureEnabled && acceptTypes.contains("video/*");
|
||||
if ((capturePhoto || captureVideo)) {
|
||||
if (isMediaCaptureSupported()) {
|
||||
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo);
|
||||
} else {
|
||||
permissionListener = (isGranted) -> {
|
||||
if (isGranted) {
|
||||
showMediaCaptureOrFilePicker(filePathCallback, fileChooserParams, captureVideo);
|
||||
} else {
|
||||
Logger.warn(Logger.tags("FileChooser"), "Camera permission not granted");
|
||||
filePathCallback.onReceiveValue(null);
|
||||
}
|
||||
};
|
||||
final String[] camPermission = { Manifest.permission.CAMERA };
|
||||
permissionLauncher.launch(camPermission);
|
||||
}
|
||||
} else {
|
||||
showFilePicker(filePathCallback, fileChooserParams);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isMediaCaptureSupported() {
|
||||
String[] permissions = { Manifest.permission.CAMERA };
|
||||
return (
|
||||
PermissionHelper.hasPermissions(bridge.getContext(), permissions) ||
|
||||
!PermissionHelper.hasDefinedPermission(bridge.getContext(), Manifest.permission.CAMERA)
|
||||
);
|
||||
}
|
||||
|
||||
private void showMediaCaptureOrFilePicker(ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams, boolean isVideo) {
|
||||
boolean shown;
|
||||
if (isVideo) {
|
||||
shown = showVideoCapturePicker(filePathCallback);
|
||||
} else {
|
||||
shown = showImageCapturePicker(filePathCallback);
|
||||
}
|
||||
if (!shown) {
|
||||
Logger.warn(Logger.tags("FileChooser"), "Media capture intent could not be launched. Falling back to default file picker.");
|
||||
showFilePicker(filePathCallback, fileChooserParams);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
private boolean showImageCapturePicker(final ValueCallback<Uri[]> filePathCallback) {
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(bridge.getActivity().getPackageManager()) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Uri imageFileUri;
|
||||
try {
|
||||
imageFileUri = createImageFileUri();
|
||||
} catch (Exception ex) {
|
||||
Logger.error("Unable to create temporary media capture file: " + ex.getMessage());
|
||||
return false;
|
||||
}
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
|
||||
activityListener = (activityResult) -> {
|
||||
Uri[] result = null;
|
||||
if (activityResult.getResultCode() == Activity.RESULT_OK) {
|
||||
result = new Uri[] { imageFileUri };
|
||||
}
|
||||
filePathCallback.onReceiveValue(result);
|
||||
};
|
||||
activityLauncher.launch(takePictureIntent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint("QueryPermissionsNeeded")
|
||||
private boolean showVideoCapturePicker(final ValueCallback<Uri[]> filePathCallback) {
|
||||
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
|
||||
if (takeVideoIntent.resolveActivity(bridge.getActivity().getPackageManager()) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
activityListener = (activityResult) -> {
|
||||
Uri[] result = null;
|
||||
if (activityResult.getResultCode() == Activity.RESULT_OK) {
|
||||
result = new Uri[] { activityResult.getData().getData() };
|
||||
}
|
||||
filePathCallback.onReceiveValue(result);
|
||||
};
|
||||
activityLauncher.launch(takeVideoIntent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void showFilePicker(final ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
|
||||
Intent intent = fileChooserParams.createIntent();
|
||||
if (fileChooserParams.getMode() == FileChooserParams.MODE_OPEN_MULTIPLE) {
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
}
|
||||
if (fileChooserParams.getAcceptTypes().length > 1 || intent.getType().startsWith(".")) {
|
||||
String[] validTypes = getValidTypes(fileChooserParams.getAcceptTypes());
|
||||
intent.putExtra(Intent.EXTRA_MIME_TYPES, validTypes);
|
||||
if (intent.getType().startsWith(".")) {
|
||||
intent.setType(validTypes[0]);
|
||||
}
|
||||
}
|
||||
try {
|
||||
activityListener = (activityResult) -> {
|
||||
Uri[] result;
|
||||
Intent resultIntent = activityResult.getData();
|
||||
if (activityResult.getResultCode() == Activity.RESULT_OK && resultIntent.getClipData() != null) {
|
||||
final int numFiles = resultIntent.getClipData().getItemCount();
|
||||
result = new Uri[numFiles];
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
result[i] = resultIntent.getClipData().getItemAt(i).getUri();
|
||||
}
|
||||
} else {
|
||||
result = WebChromeClient.FileChooserParams.parseResult(activityResult.getResultCode(), resultIntent);
|
||||
}
|
||||
filePathCallback.onReceiveValue(result);
|
||||
};
|
||||
activityLauncher.launch(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
filePathCallback.onReceiveValue(null);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] getValidTypes(String[] currentTypes) {
|
||||
List<String> validTypes = new ArrayList<>();
|
||||
MimeTypeMap mtm = MimeTypeMap.getSingleton();
|
||||
for (String mime : currentTypes) {
|
||||
if (mime.startsWith(".")) {
|
||||
String extension = mime.substring(1);
|
||||
String extensionMime = mtm.getMimeTypeFromExtension(extension);
|
||||
if (extensionMime != null && !validTypes.contains(extensionMime)) {
|
||||
validTypes.add(extensionMime);
|
||||
}
|
||||
} else if (!validTypes.contains(mime)) {
|
||||
validTypes.add(mime);
|
||||
}
|
||||
}
|
||||
Object[] validObj = validTypes.toArray();
|
||||
return Arrays.copyOf(validObj, validObj.length, String[].class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
|
||||
String tag = Logger.tags("Console");
|
||||
if (consoleMessage.message() != null && isValidMsg(consoleMessage.message())) {
|
||||
String msg = String.format(
|
||||
"File: %s - Line %d - Msg: %s",
|
||||
consoleMessage.sourceId(),
|
||||
consoleMessage.lineNumber(),
|
||||
consoleMessage.message()
|
||||
);
|
||||
String level = consoleMessage.messageLevel().name();
|
||||
if ("ERROR".equalsIgnoreCase(level)) {
|
||||
Logger.error(tag, msg, null);
|
||||
} else if ("WARNING".equalsIgnoreCase(level)) {
|
||||
Logger.warn(tag, msg);
|
||||
} else if ("TIP".equalsIgnoreCase(level)) {
|
||||
Logger.debug(tag, msg);
|
||||
} else {
|
||||
Logger.info(tag, msg);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isValidMsg(String msg) {
|
||||
return !(msg.contains("%cresult %c") || (msg.contains("%cnative %c")) || msg.equalsIgnoreCase("console.groupEnd"));
|
||||
}
|
||||
|
||||
private Uri createImageFileUri() throws IOException {
|
||||
Activity activity = bridge.getActivity();
|
||||
File photoFile = createImageFile(activity);
|
||||
return FileProvider.getUriForFile(activity, bridge.getContext().getPackageName() + ".fileprovider", photoFile);
|
||||
}
|
||||
|
||||
private File createImageFile(Activity activity) throws IOException {
|
||||
// Create an image file name
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
|
||||
return File.createTempFile(imageFileName, ".jpg", storageDir);
|
||||
}
|
||||
}
|
||||
117
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java
generated
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.webkit.RenderProcessGoneDetail;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebResourceResponse;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import java.util.List;
|
||||
|
||||
public class BridgeWebViewClient extends WebViewClient {
|
||||
|
||||
private Bridge bridge;
|
||||
|
||||
public BridgeWebViewClient(Bridge bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
|
||||
return bridge.getLocalServer().shouldInterceptRequest(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
|
||||
Uri url = request.getUrl();
|
||||
return bridge.launchIntent(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
|
||||
if (webViewListeners != null && view.getProgress() == 100) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
listener.onPageLoaded(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
super.onReceivedError(view, request, error);
|
||||
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
if (webViewListeners != null) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
listener.onReceivedError(view);
|
||||
}
|
||||
}
|
||||
|
||||
String errorPath = bridge.getErrorUrl();
|
||||
if (errorPath != null && request.isForMainFrame()) {
|
||||
view.loadUrl(errorPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
bridge.reset();
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
|
||||
if (webViewListeners != null) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
listener.onPageStarted(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
|
||||
super.onReceivedHttpError(view, request, errorResponse);
|
||||
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
if (webViewListeners != null) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
listener.onReceivedHttpError(view);
|
||||
}
|
||||
}
|
||||
|
||||
String errorPath = bridge.getErrorUrl();
|
||||
if (errorPath != null && request.isForMainFrame()) {
|
||||
view.loadUrl(errorPath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
|
||||
super.onRenderProcessGone(view, detail);
|
||||
boolean result = false;
|
||||
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
if (webViewListeners != null) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
result = listener.onRenderProcessGone(view, detail) || result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageCommitVisible(WebView view, String url) {
|
||||
super.onPageCommitVisible(view, url);
|
||||
|
||||
List<WebViewListener> webViewListeners = bridge.getWebViewListeners();
|
||||
if (webViewListeners != null) {
|
||||
for (WebViewListener listener : bridge.getWebViewListeners()) {
|
||||
listener.onPageCommitVisible(view, url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
709
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapConfig.java
generated
vendored
Normal file
|
|
@ -0,0 +1,709 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import static com.getcapacitor.Bridge.CAPACITOR_HTTPS_SCHEME;
|
||||
import static com.getcapacitor.Bridge.DEFAULT_ANDROID_WEBVIEW_VERSION;
|
||||
import static com.getcapacitor.Bridge.DEFAULT_HUAWEI_WEBVIEW_VERSION;
|
||||
import static com.getcapacitor.Bridge.MINIMUM_ANDROID_WEBVIEW_VERSION;
|
||||
import static com.getcapacitor.Bridge.MINIMUM_HUAWEI_WEBVIEW_VERSION;
|
||||
import static com.getcapacitor.FileUtils.readFileFromAssets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.AssetManager;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.getcapacitor.util.JSONUtils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents the configuration options for Capacitor
|
||||
*/
|
||||
public class CapConfig {
|
||||
|
||||
private static final String LOG_BEHAVIOR_NONE = "none";
|
||||
private static final String LOG_BEHAVIOR_DEBUG = "debug";
|
||||
private static final String LOG_BEHAVIOR_PRODUCTION = "production";
|
||||
|
||||
// Server Config
|
||||
private boolean html5mode = true;
|
||||
private String serverUrl;
|
||||
private String hostname = "localhost";
|
||||
private String androidScheme = CAPACITOR_HTTPS_SCHEME;
|
||||
private String[] allowNavigation;
|
||||
|
||||
// Android Config
|
||||
private String overriddenUserAgentString;
|
||||
private String appendedUserAgentString;
|
||||
private String backgroundColor;
|
||||
private boolean allowMixedContent = false;
|
||||
private boolean captureInput = false;
|
||||
private boolean webContentsDebuggingEnabled = false;
|
||||
private boolean loggingEnabled = true;
|
||||
private boolean initialFocus = true;
|
||||
private boolean useLegacyBridge = false;
|
||||
private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION;
|
||||
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
|
||||
private String errorPath;
|
||||
private boolean zoomableWebView = false;
|
||||
private boolean resolveServiceWorkerRequests = true;
|
||||
|
||||
// Embedded
|
||||
private String startPath;
|
||||
|
||||
// Plugins
|
||||
private Map<String, PluginConfig> pluginsConfiguration = null;
|
||||
|
||||
// Config Object JSON (legacy)
|
||||
private JSONObject configJSON = new JSONObject();
|
||||
|
||||
/**
|
||||
* Constructs an empty config file.
|
||||
*/
|
||||
private CapConfig() {}
|
||||
|
||||
/**
|
||||
* Get an instance of the Config file object.
|
||||
* @deprecated use {@link #loadDefault(Context)} to load an instance of the Config object
|
||||
* from the capacitor.config.json file, or use the {@link CapConfig.Builder} to construct
|
||||
* a CapConfig for embedded use.
|
||||
*
|
||||
* @param assetManager The AssetManager used to load the config file
|
||||
* @param config JSON describing a configuration to use
|
||||
*/
|
||||
@Deprecated
|
||||
public CapConfig(AssetManager assetManager, JSONObject config) {
|
||||
if (config != null) {
|
||||
this.configJSON = config;
|
||||
} else {
|
||||
// Load the capacitor.config.json
|
||||
loadConfigFromAssets(assetManager, null);
|
||||
}
|
||||
|
||||
deserializeConfig(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Capacitor Configuration from config.json file.
|
||||
*
|
||||
* @param context The context.
|
||||
* @return A loaded config file, if successful.
|
||||
*/
|
||||
public static CapConfig loadDefault(Context context) {
|
||||
CapConfig config = new CapConfig();
|
||||
|
||||
if (context == null) {
|
||||
Logger.error("Capacitor Config could not be created from file. Context must not be null.");
|
||||
return config;
|
||||
}
|
||||
|
||||
config.loadConfigFromAssets(context.getAssets(), null);
|
||||
config.deserializeConfig(context);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Capacitor Configuration from config.json file within the app assets.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param path A path relative to the root assets directory.
|
||||
* @return A loaded config file, if successful.
|
||||
*/
|
||||
public static CapConfig loadFromAssets(Context context, String path) {
|
||||
CapConfig config = new CapConfig();
|
||||
|
||||
if (context == null) {
|
||||
Logger.error("Capacitor Config could not be created from file. Context must not be null.");
|
||||
return config;
|
||||
}
|
||||
|
||||
config.loadConfigFromAssets(context.getAssets(), path);
|
||||
config.deserializeConfig(context);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Capacitor Configuration from config.json file within the app file-space.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param path A path relative to the root of the app file-space.
|
||||
* @return A loaded config file, if successful.
|
||||
*/
|
||||
public static CapConfig loadFromFile(Context context, String path) {
|
||||
CapConfig config = new CapConfig();
|
||||
|
||||
if (context == null) {
|
||||
Logger.error("Capacitor Config could not be created from file. Context must not be null.");
|
||||
return config;
|
||||
}
|
||||
|
||||
config.loadConfigFromFile(path);
|
||||
config.deserializeConfig(context);
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Capacitor Configuration using ConfigBuilder.
|
||||
*
|
||||
* @param builder A config builder initialized with values
|
||||
*/
|
||||
private CapConfig(Builder builder) {
|
||||
// Server Config
|
||||
this.html5mode = builder.html5mode;
|
||||
this.serverUrl = builder.serverUrl;
|
||||
this.hostname = builder.hostname;
|
||||
|
||||
if (this.validateScheme(builder.androidScheme)) {
|
||||
this.androidScheme = builder.androidScheme;
|
||||
}
|
||||
|
||||
this.allowNavigation = builder.allowNavigation;
|
||||
|
||||
// Android Config
|
||||
this.overriddenUserAgentString = builder.overriddenUserAgentString;
|
||||
this.appendedUserAgentString = builder.appendedUserAgentString;
|
||||
this.backgroundColor = builder.backgroundColor;
|
||||
this.allowMixedContent = builder.allowMixedContent;
|
||||
this.captureInput = builder.captureInput;
|
||||
this.webContentsDebuggingEnabled = builder.webContentsDebuggingEnabled;
|
||||
this.loggingEnabled = builder.loggingEnabled;
|
||||
this.initialFocus = builder.initialFocus;
|
||||
this.useLegacyBridge = builder.useLegacyBridge;
|
||||
this.minWebViewVersion = builder.minWebViewVersion;
|
||||
this.minHuaweiWebViewVersion = builder.minHuaweiWebViewVersion;
|
||||
this.errorPath = builder.errorPath;
|
||||
this.zoomableWebView = builder.zoomableWebView;
|
||||
this.resolveServiceWorkerRequests = builder.resolveServiceWorkerRequests;
|
||||
|
||||
// Embedded
|
||||
this.startPath = builder.startPath;
|
||||
|
||||
// Plugins Config
|
||||
this.pluginsConfiguration = builder.pluginsConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Capacitor Configuration JSON file into a Capacitor Configuration object.
|
||||
* An optional path string can be provided to look for the config in a subdirectory path.
|
||||
*/
|
||||
private void loadConfigFromAssets(AssetManager assetManager, String path) {
|
||||
if (path == null) {
|
||||
path = "";
|
||||
} else {
|
||||
// Add slash at the end to form a proper file path if going deeper in assets dir
|
||||
if (path.charAt(path.length() - 1) != '/') {
|
||||
path = path + "/";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String jsonString = readFileFromAssets(assetManager, path + "capacitor.config.json");
|
||||
configJSON = new JSONObject(jsonString);
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Unable to load capacitor.config.json. Run npx cap copy first", ex);
|
||||
} catch (JSONException ex) {
|
||||
Logger.error("Unable to parse capacitor.config.json. Make sure it's valid json", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a Capacitor Configuration JSON file into a Capacitor Configuration object.
|
||||
* An optional path string can be provided to look for the config in a subdirectory path.
|
||||
*/
|
||||
private void loadConfigFromFile(String path) {
|
||||
if (path == null) {
|
||||
path = "";
|
||||
} else {
|
||||
// Add slash at the end to form a proper file path if going deeper in assets dir
|
||||
if (path.charAt(path.length() - 1) != '/') {
|
||||
path = path + "/";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File configFile = new File(path + "capacitor.config.json");
|
||||
String jsonString = FileUtils.readFileFromDisk(configFile);
|
||||
configJSON = new JSONObject(jsonString);
|
||||
} catch (JSONException ex) {
|
||||
Logger.error("Unable to parse capacitor.config.json. Make sure it's valid json", ex);
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Unable to load capacitor.config.json.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the config from JSON into a Capacitor Configuration object.
|
||||
*/
|
||||
private void deserializeConfig(@Nullable Context context) {
|
||||
boolean isDebug = context != null && (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
|
||||
// Server
|
||||
html5mode = JSONUtils.getBoolean(configJSON, "server.html5mode", html5mode);
|
||||
serverUrl = JSONUtils.getString(configJSON, "server.url", null);
|
||||
hostname = JSONUtils.getString(configJSON, "server.hostname", hostname);
|
||||
errorPath = JSONUtils.getString(configJSON, "server.errorPath", null);
|
||||
startPath = JSONUtils.getString(configJSON, "server.appStartPath", null);
|
||||
|
||||
String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme);
|
||||
if (this.validateScheme(configSchema)) {
|
||||
androidScheme = configSchema;
|
||||
}
|
||||
|
||||
allowNavigation = JSONUtils.getArray(configJSON, "server.allowNavigation", null);
|
||||
|
||||
// Android
|
||||
overriddenUserAgentString = JSONUtils.getString(
|
||||
configJSON,
|
||||
"android.overrideUserAgent",
|
||||
JSONUtils.getString(configJSON, "overrideUserAgent", null)
|
||||
);
|
||||
appendedUserAgentString = JSONUtils.getString(
|
||||
configJSON,
|
||||
"android.appendUserAgent",
|
||||
JSONUtils.getString(configJSON, "appendUserAgent", null)
|
||||
);
|
||||
backgroundColor = JSONUtils.getString(
|
||||
configJSON,
|
||||
"android.backgroundColor",
|
||||
JSONUtils.getString(configJSON, "backgroundColor", null)
|
||||
);
|
||||
allowMixedContent = JSONUtils.getBoolean(
|
||||
configJSON,
|
||||
"android.allowMixedContent",
|
||||
JSONUtils.getBoolean(configJSON, "allowMixedContent", allowMixedContent)
|
||||
);
|
||||
minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION);
|
||||
minHuaweiWebViewVersion = JSONUtils.getInt(configJSON, "android.minHuaweiWebViewVersion", DEFAULT_HUAWEI_WEBVIEW_VERSION);
|
||||
captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput);
|
||||
useLegacyBridge = JSONUtils.getBoolean(configJSON, "android.useLegacyBridge", useLegacyBridge);
|
||||
webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug);
|
||||
zoomableWebView = JSONUtils.getBoolean(configJSON, "android.zoomEnabled", JSONUtils.getBoolean(configJSON, "zoomEnabled", false));
|
||||
resolveServiceWorkerRequests = JSONUtils.getBoolean(configJSON, "android.resolveServiceWorkerRequests", true);
|
||||
|
||||
String logBehavior = JSONUtils.getString(
|
||||
configJSON,
|
||||
"android.loggingBehavior",
|
||||
JSONUtils.getString(configJSON, "loggingBehavior", LOG_BEHAVIOR_DEBUG)
|
||||
);
|
||||
switch (logBehavior.toLowerCase(Locale.ROOT)) {
|
||||
case LOG_BEHAVIOR_PRODUCTION:
|
||||
loggingEnabled = true;
|
||||
break;
|
||||
case LOG_BEHAVIOR_NONE:
|
||||
loggingEnabled = false;
|
||||
break;
|
||||
default: // LOG_BEHAVIOR_DEBUG
|
||||
loggingEnabled = isDebug;
|
||||
}
|
||||
|
||||
initialFocus = JSONUtils.getBoolean(
|
||||
configJSON,
|
||||
"android.initialFocus",
|
||||
JSONUtils.getBoolean(configJSON, "initialFocus", initialFocus)
|
||||
);
|
||||
|
||||
// Plugins
|
||||
pluginsConfiguration = deserializePluginsConfig(JSONUtils.getObject(configJSON, "plugins"));
|
||||
}
|
||||
|
||||
private boolean validateScheme(String scheme) {
|
||||
List<String> invalidSchemes = Arrays.asList("file", "ftp", "ftps", "ws", "wss", "about", "blob", "data");
|
||||
if (invalidSchemes.contains(scheme)) {
|
||||
Logger.warn(scheme + " is not an allowed scheme. Defaulting to https.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Non-http(s) schemes are not allowed to modify the URL path as of Android Webview 117
|
||||
if (!scheme.equals("http") && !scheme.equals("https")) {
|
||||
Logger.warn(
|
||||
"Using a non-standard scheme: " + scheme + " for Android. This is known to cause issues as of Android Webview 117."
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isHTML5Mode() {
|
||||
return html5mode;
|
||||
}
|
||||
|
||||
public String getServerUrl() {
|
||||
return serverUrl;
|
||||
}
|
||||
|
||||
public String getErrorPath() {
|
||||
return errorPath;
|
||||
}
|
||||
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
public String getStartPath() {
|
||||
return startPath;
|
||||
}
|
||||
|
||||
public String getAndroidScheme() {
|
||||
return androidScheme;
|
||||
}
|
||||
|
||||
public String[] getAllowNavigation() {
|
||||
return allowNavigation;
|
||||
}
|
||||
|
||||
public String getOverriddenUserAgentString() {
|
||||
return overriddenUserAgentString;
|
||||
}
|
||||
|
||||
public String getAppendedUserAgentString() {
|
||||
return appendedUserAgentString;
|
||||
}
|
||||
|
||||
public String getBackgroundColor() {
|
||||
return backgroundColor;
|
||||
}
|
||||
|
||||
public boolean isMixedContentAllowed() {
|
||||
return allowMixedContent;
|
||||
}
|
||||
|
||||
public boolean isInputCaptured() {
|
||||
return captureInput;
|
||||
}
|
||||
|
||||
public boolean isResolveServiceWorkerRequests() {
|
||||
return resolveServiceWorkerRequests;
|
||||
}
|
||||
|
||||
public boolean isWebContentsDebuggingEnabled() {
|
||||
return webContentsDebuggingEnabled;
|
||||
}
|
||||
|
||||
public boolean isZoomableWebView() {
|
||||
return zoomableWebView;
|
||||
}
|
||||
|
||||
public boolean isLoggingEnabled() {
|
||||
return loggingEnabled;
|
||||
}
|
||||
|
||||
public boolean isInitialFocus() {
|
||||
return initialFocus;
|
||||
}
|
||||
|
||||
public boolean isUsingLegacyBridge() {
|
||||
return useLegacyBridge;
|
||||
}
|
||||
|
||||
public int getMinWebViewVersion() {
|
||||
if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) {
|
||||
Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION);
|
||||
return MINIMUM_ANDROID_WEBVIEW_VERSION;
|
||||
}
|
||||
|
||||
return minWebViewVersion;
|
||||
}
|
||||
|
||||
public int getMinHuaweiWebViewVersion() {
|
||||
if (minHuaweiWebViewVersion < MINIMUM_HUAWEI_WEBVIEW_VERSION) {
|
||||
Logger.warn("Specified minimum Huawei webview version is too low, defaulting to " + MINIMUM_HUAWEI_WEBVIEW_VERSION);
|
||||
return MINIMUM_HUAWEI_WEBVIEW_VERSION;
|
||||
}
|
||||
|
||||
return minHuaweiWebViewVersion;
|
||||
}
|
||||
|
||||
public PluginConfig getPluginConfiguration(String pluginId) {
|
||||
PluginConfig pluginConfig = pluginsConfiguration.get(pluginId);
|
||||
if (pluginConfig == null) {
|
||||
pluginConfig = new PluginConfig(new JSONObject());
|
||||
}
|
||||
|
||||
return pluginConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON object value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getObject(String)} to access plugin config values.
|
||||
* For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
@Deprecated
|
||||
public JSONObject getObject(String key) {
|
||||
try {
|
||||
return configJSON.getJSONObject(key);
|
||||
} catch (Exception ex) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getString(String, String)} to access plugin config
|
||||
* values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
@Deprecated
|
||||
public String getString(String key) {
|
||||
return JSONUtils.getString(configJSON, key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getString(String, String)} to access plugin config
|
||||
* values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
@Deprecated
|
||||
public String getString(String key, String defaultValue) {
|
||||
return JSONUtils.getString(configJSON, key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getBoolean(String, boolean)} to access plugin config
|
||||
* values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return JSONUtils.getBoolean(configJSON, key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an integer value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getInt(String, int)} to access the plugin config
|
||||
* values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
@Deprecated
|
||||
public int getInt(String key, int defaultValue) {
|
||||
return JSONUtils.getInt(configJSON, key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string array value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getArray(String)} to access the plugin config
|
||||
* values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
@Deprecated
|
||||
public String[] getArray(String key) {
|
||||
return JSONUtils.getArray(configJSON, key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string array value from the Capacitor config.
|
||||
* @deprecated use {@link PluginConfig#getArray(String, String[])} to access the plugin
|
||||
* config values. For main Capacitor config values, use the appropriate getter.
|
||||
*
|
||||
* @param key A key to fetch from the config
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
@Deprecated
|
||||
public String[] getArray(String key, String[] defaultValue) {
|
||||
return JSONUtils.getArray(configJSON, key, defaultValue);
|
||||
}
|
||||
|
||||
private static Map<String, PluginConfig> deserializePluginsConfig(JSONObject pluginsConfig) {
|
||||
Map<String, PluginConfig> pluginsMap = new HashMap<>();
|
||||
|
||||
// return an empty map if there is no pluginsConfig json
|
||||
if (pluginsConfig == null) {
|
||||
return pluginsMap;
|
||||
}
|
||||
|
||||
Iterator<String> pluginIds = pluginsConfig.keys();
|
||||
|
||||
while (pluginIds.hasNext()) {
|
||||
String pluginId = pluginIds.next();
|
||||
JSONObject value = null;
|
||||
|
||||
try {
|
||||
value = pluginsConfig.getJSONObject(pluginId);
|
||||
PluginConfig pluginConfig = new PluginConfig(value);
|
||||
pluginsMap.put(pluginId, pluginConfig);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return pluginsMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Capacitor Configuration in code
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private Context context;
|
||||
|
||||
// Server Config Values
|
||||
private boolean html5mode = true;
|
||||
private String serverUrl;
|
||||
private String errorPath;
|
||||
private String hostname = "localhost";
|
||||
private String androidScheme = CAPACITOR_HTTPS_SCHEME;
|
||||
private String[] allowNavigation;
|
||||
|
||||
// Android Config Values
|
||||
private String overriddenUserAgentString;
|
||||
private String appendedUserAgentString;
|
||||
private String backgroundColor;
|
||||
private boolean allowMixedContent = false;
|
||||
private boolean captureInput = false;
|
||||
private Boolean webContentsDebuggingEnabled = null;
|
||||
private boolean loggingEnabled = true;
|
||||
private boolean initialFocus = false;
|
||||
private boolean useLegacyBridge = false;
|
||||
private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION;
|
||||
private int minHuaweiWebViewVersion = DEFAULT_HUAWEI_WEBVIEW_VERSION;
|
||||
private boolean zoomableWebView = false;
|
||||
private boolean resolveServiceWorkerRequests = true;
|
||||
|
||||
// Embedded
|
||||
private String startPath = null;
|
||||
|
||||
// Plugins Config Object
|
||||
private Map<String, PluginConfig> pluginsConfiguration = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new CapConfig Builder.
|
||||
*
|
||||
* @param context The context
|
||||
*/
|
||||
public Builder(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Capacitor Config from the builder.
|
||||
*
|
||||
* @return A new Capacitor Config
|
||||
*/
|
||||
public CapConfig create() {
|
||||
if (webContentsDebuggingEnabled == null) {
|
||||
webContentsDebuggingEnabled = (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
|
||||
}
|
||||
|
||||
return new CapConfig(this);
|
||||
}
|
||||
|
||||
public Builder setPluginsConfiguration(JSONObject pluginsConfiguration) {
|
||||
this.pluginsConfiguration = deserializePluginsConfig(pluginsConfiguration);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHTML5mode(boolean html5mode) {
|
||||
this.html5mode = html5mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setServerUrl(String serverUrl) {
|
||||
this.serverUrl = serverUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setErrorPath(String errorPath) {
|
||||
this.errorPath = errorPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setStartPath(String path) {
|
||||
this.startPath = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAndroidScheme(String androidScheme) {
|
||||
this.androidScheme = androidScheme;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAllowNavigation(String[] allowNavigation) {
|
||||
this.allowNavigation = allowNavigation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setOverriddenUserAgentString(String overriddenUserAgentString) {
|
||||
this.overriddenUserAgentString = overriddenUserAgentString;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAppendedUserAgentString(String appendedUserAgentString) {
|
||||
this.appendedUserAgentString = appendedUserAgentString;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBackgroundColor(String backgroundColor) {
|
||||
this.backgroundColor = backgroundColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAllowMixedContent(boolean allowMixedContent) {
|
||||
this.allowMixedContent = allowMixedContent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCaptureInput(boolean captureInput) {
|
||||
this.captureInput = captureInput;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setUseLegacyBridge(boolean useLegacyBridge) {
|
||||
this.useLegacyBridge = useLegacyBridge;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setResolveServiceWorkerRequests(boolean resolveServiceWorkerRequests) {
|
||||
this.resolveServiceWorkerRequests = resolveServiceWorkerRequests;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setWebContentsDebuggingEnabled(boolean webContentsDebuggingEnabled) {
|
||||
this.webContentsDebuggingEnabled = webContentsDebuggingEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setZoomableWebView(boolean zoomableWebView) {
|
||||
this.zoomableWebView = zoomableWebView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setLoggingEnabled(boolean enabled) {
|
||||
this.loggingEnabled = enabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setInitialFocus(boolean focus) {
|
||||
this.initialFocus = focus;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.inputmethod.BaseInputConnection;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.webkit.WebView;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
public class CapacitorWebView extends WebView {
|
||||
|
||||
private BaseInputConnection capInputConnection;
|
||||
private Bridge bridge;
|
||||
|
||||
public CapacitorWebView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void setBridge(Bridge bridge) {
|
||||
this.bridge = bridge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
CapConfig config;
|
||||
if (bridge != null) {
|
||||
config = bridge.getConfig();
|
||||
} else {
|
||||
config = CapConfig.loadDefault(getContext());
|
||||
}
|
||||
|
||||
boolean captureInput = config.isInputCaptured();
|
||||
if (captureInput) {
|
||||
if (capInputConnection == null) {
|
||||
capInputConnection = new BaseInputConnection(this, false);
|
||||
}
|
||||
return capInputConnection;
|
||||
}
|
||||
return super.onCreateInputConnection(outAttrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
|
||||
evaluateJavascript("document.activeElement.value = document.activeElement.value + '" + event.getCharacters() + "';", null);
|
||||
return false;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
303
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/FileUtils.java
generated
vendored
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/**
|
||||
* Portions adopted from react-native-image-crop-picker
|
||||
*
|
||||
* MIT License
|
||||
|
||||
* Copyright (c) 2017 Ivan Pusic
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
package com.getcapacitor;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.provider.DocumentsContract;
|
||||
import android.provider.MediaStore;
|
||||
import android.provider.OpenableColumns;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* Common File utilities, such as resolve content URIs and
|
||||
* creating portable web paths from low-level files
|
||||
*/
|
||||
public class FileUtils {
|
||||
|
||||
private static String CapacitorFileScheme = Bridge.CAPACITOR_FILE_START;
|
||||
|
||||
public enum Type {
|
||||
IMAGE("image");
|
||||
|
||||
private String type;
|
||||
|
||||
Type(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getPortablePath(Context c, String host, Uri u) {
|
||||
String path = getFileUrlForUri(c, u);
|
||||
if (path.startsWith("file://")) {
|
||||
path = path.replace("file://", "");
|
||||
}
|
||||
return host + Bridge.CAPACITOR_FILE_START + path;
|
||||
}
|
||||
|
||||
public static String getFileUrlForUri(final Context context, final Uri uri) {
|
||||
// DocumentProvider
|
||||
if (DocumentsContract.isDocumentUri(context, uri)) {
|
||||
// ExternalStorageProvider
|
||||
if (isExternalStorageDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
if ("primary".equalsIgnoreCase(type)) {
|
||||
return legacyPrimaryPath(split[1]);
|
||||
} else {
|
||||
final int splitIndex = docId.indexOf(':', 1);
|
||||
final String tag = docId.substring(0, splitIndex);
|
||||
final String path = docId.substring(splitIndex + 1);
|
||||
|
||||
String nonPrimaryVolume = getPathToNonPrimaryVolume(context, tag);
|
||||
if (nonPrimaryVolume != null) {
|
||||
String result = nonPrimaryVolume + "/" + path;
|
||||
File file = new File(result);
|
||||
if (file.exists() && file.canRead()) {
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// DownloadsProvider
|
||||
else if (isDownloadsDocument(uri)) {
|
||||
final String id = DocumentsContract.getDocumentId(uri);
|
||||
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
|
||||
|
||||
return getDataColumn(context, contentUri, null, null);
|
||||
}
|
||||
// MediaProvider
|
||||
else if (isMediaDocument(uri)) {
|
||||
final String docId = DocumentsContract.getDocumentId(uri);
|
||||
final String[] split = docId.split(":");
|
||||
final String type = split[0];
|
||||
|
||||
Uri contentUri = null;
|
||||
if ("image".equals(type)) {
|
||||
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("video".equals(type)) {
|
||||
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||
} else if ("audio".equals(type)) {
|
||||
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
|
||||
final String selection = "_id=?";
|
||||
final String[] selectionArgs = new String[] { split[1] };
|
||||
|
||||
return getDataColumn(context, contentUri, selection, selectionArgs);
|
||||
}
|
||||
}
|
||||
// MediaStore (and general)
|
||||
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||
// Return the remote address
|
||||
if (isGooglePhotosUri(uri)) return uri.getLastPathSegment();
|
||||
return getDataColumn(context, uri, null, null);
|
||||
}
|
||||
// File
|
||||
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||
return uri.getPath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static String legacyPrimaryPath(String pathPart) {
|
||||
return Environment.getExternalStorageDirectory() + "/" + pathPart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a plaintext file from the assets directory.
|
||||
*
|
||||
* @param assetManager Used to open the file.
|
||||
* @param fileName The path of the file to read.
|
||||
* @return The contents of the file path.
|
||||
* @throws IOException Thrown if any issues reading the provided file path.
|
||||
*/
|
||||
static String readFileFromAssets(AssetManager assetManager, String fileName) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open(fileName)))) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a plaintext file from within the app disk space.
|
||||
*
|
||||
* @param file The file to read.
|
||||
* @return The contents of the file path.
|
||||
* @throws IOException Thrown if any issues reading the provided file path.
|
||||
*/
|
||||
static String readFileFromDisk(File file) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
buffer.append(line).append("\n");
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the data column for this Uri. This is useful for
|
||||
* MediaStore Uris, and other file-based ContentProviders.
|
||||
*
|
||||
* @param context The context.
|
||||
* @param uri The Uri to query.
|
||||
* @param selection (Optional) Filter used in the query.
|
||||
* @param selectionArgs (Optional) Selection arguments used in the query.
|
||||
* @return The value of the _data column, which is typically a file path.
|
||||
*/
|
||||
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
|
||||
String path = null;
|
||||
Cursor cursor = null;
|
||||
final String column = "_data";
|
||||
final String[] projection = { column };
|
||||
|
||||
try {
|
||||
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final int index = cursor.getColumnIndexOrThrow(column);
|
||||
path = cursor.getString(index);
|
||||
}
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return getCopyFilePath(uri, context);
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
if (path == null) {
|
||||
return getCopyFilePath(uri, context);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private static String getCopyFilePath(Uri uri, Context context) {
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
|
||||
cursor.moveToFirst();
|
||||
String name = (cursor.getString(nameIndex));
|
||||
String fileName = sanitizeFilename(name);
|
||||
File file = new File(context.getFilesDir(), fileName);
|
||||
try {
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(uri);
|
||||
FileOutputStream outputStream = new FileOutputStream(file);
|
||||
int read = 0;
|
||||
int maxBufferSize = 1024 * 1024;
|
||||
int bufferSize = Math.min(inputStream.available(), maxBufferSize);
|
||||
final byte[] buffers = new byte[bufferSize];
|
||||
while ((read = inputStream.read(buffers)) != -1) {
|
||||
outputStream.write(buffers, 0, read);
|
||||
}
|
||||
inputStream.close();
|
||||
outputStream.close();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
return file.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||
*/
|
||||
private static boolean isExternalStorageDocument(Uri uri) {
|
||||
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is DownloadsProvider.
|
||||
*/
|
||||
private static boolean isDownloadsDocument(Uri uri) {
|
||||
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is MediaProvider.
|
||||
*/
|
||||
private static boolean isMediaDocument(Uri uri) {
|
||||
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param uri The Uri to check.
|
||||
* @return Whether the Uri authority is Google Photos.
|
||||
*/
|
||||
private static boolean isGooglePhotosUri(Uri uri) {
|
||||
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
|
||||
}
|
||||
|
||||
private static String getPathToNonPrimaryVolume(Context context, String tag) {
|
||||
File[] volumes = context.getExternalCacheDirs();
|
||||
if (volumes != null) {
|
||||
for (File volume : volumes) {
|
||||
if (volume != null) {
|
||||
String path = volume.getAbsolutePath();
|
||||
if (path != null) {
|
||||
int index = path.indexOf(tag);
|
||||
if (index != -1) {
|
||||
return path.substring(0, index) + tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String sanitizeFilename(String displayName) {
|
||||
String[] badCharacters = new String[] { "..", "/" };
|
||||
String[] segments = displayName.split("/");
|
||||
String fileName = segments[segments.length - 1];
|
||||
for (String suspString : badCharacters) {
|
||||
fileName = fileName.replace(suspString, "_");
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
8
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginException.java
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
class InvalidPluginException extends Exception {
|
||||
|
||||
public InvalidPluginException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
16
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/InvalidPluginMethodException.java
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
class InvalidPluginMethodException extends Exception {
|
||||
|
||||
public InvalidPluginMethodException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public InvalidPluginMethodException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public InvalidPluginMethodException(String s, Throwable t) {
|
||||
super(s, t);
|
||||
}
|
||||
}
|
||||
51
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSArray.java
generated
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
public class JSArray extends JSONArray {
|
||||
|
||||
public JSArray() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JSArray(String json) throws JSONException {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public JSArray(Collection copyFrom) {
|
||||
super(copyFrom);
|
||||
}
|
||||
|
||||
public JSArray(Object array) throws JSONException {
|
||||
super(array);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <E> List<E> toList() throws JSONException {
|
||||
List<E> items = new ArrayList<>();
|
||||
Object o = null;
|
||||
for (int i = 0; i < this.length(); i++) {
|
||||
o = this.get(i);
|
||||
try {
|
||||
items.add((E) this.get(i));
|
||||
} catch (Exception ex) {
|
||||
throw new JSONException("Not all items are instances of the given type");
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new JSArray without throwing a error
|
||||
*/
|
||||
public static JSArray from(Object array) {
|
||||
try {
|
||||
return new JSArray(array);
|
||||
} catch (JSONException ex) {}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
208
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExport.java
generated
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import static com.getcapacitor.FileUtils.readFileFromAssets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class JSExport {
|
||||
|
||||
private static String CATCHALL_OPTIONS_PARAM = "_options";
|
||||
private static String CALLBACK_PARAM = "_callback";
|
||||
|
||||
public static String getGlobalJS(Context context, boolean loggingEnabled, boolean isDebug) {
|
||||
return "window.Capacitor = { DEBUG: " + isDebug + ", isLoggingEnabled: " + loggingEnabled + ", Plugins: {} };";
|
||||
}
|
||||
|
||||
public static String getMiscFileJS(ArrayList<String> paths, Context context) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
for (String path : paths) {
|
||||
try {
|
||||
String fileContent = readFileFromAssets(context.getAssets(), "public/" + path);
|
||||
lines.add(fileContent);
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Unable to read public/" + path);
|
||||
}
|
||||
}
|
||||
|
||||
return TextUtils.join("\n", lines);
|
||||
}
|
||||
|
||||
public static String getCordovaJS(Context context) {
|
||||
String fileContent = "";
|
||||
try {
|
||||
fileContent = readFileFromAssets(context.getAssets(), "public/cordova.js");
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Unable to read public/cordova.js file, Cordova plugins will not work");
|
||||
}
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
public static String getCordovaPluginsFileJS(Context context) {
|
||||
String fileContent = "";
|
||||
try {
|
||||
fileContent = readFileFromAssets(context.getAssets(), "public/cordova_plugins.js");
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Unable to read public/cordova_plugins.js file, Cordova plugins will not work");
|
||||
}
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
public static String getPluginJS(Collection<PluginHandle> plugins) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
JSONArray pluginArray = new JSONArray();
|
||||
|
||||
lines.add("// Begin: Capacitor Plugin JS");
|
||||
for (PluginHandle plugin : plugins) {
|
||||
lines.add(
|
||||
"(function(w) {\n" +
|
||||
"var a = (w.Capacitor = w.Capacitor || {});\n" +
|
||||
"var p = (a.Plugins = a.Plugins || {});\n" +
|
||||
"var t = (p['" +
|
||||
plugin.getId() +
|
||||
"'] = {});\n" +
|
||||
"t.addListener = function(eventName, callback) {\n" +
|
||||
" return w.Capacitor.addListener('" +
|
||||
plugin.getId() +
|
||||
"', eventName, callback);\n" +
|
||||
"}"
|
||||
);
|
||||
Collection<PluginMethodHandle> methods = plugin.getMethods();
|
||||
for (PluginMethodHandle method : methods) {
|
||||
if (method.getName().equals("addListener") || method.getName().equals("removeListener")) {
|
||||
// Don't export add/remove listener, we do that automatically above as they are "special snowflakes"
|
||||
continue;
|
||||
}
|
||||
lines.add(generateMethodJS(plugin, method));
|
||||
}
|
||||
|
||||
lines.add("})(window);\n");
|
||||
pluginArray.put(createPluginHeader(plugin));
|
||||
}
|
||||
|
||||
return TextUtils.join("\n", lines) + "\nwindow.Capacitor.PluginHeaders = " + pluginArray.toString() + ";";
|
||||
}
|
||||
|
||||
public static String getCordovaPluginJS(Context context) {
|
||||
return getFilesContent(context, "public/plugins");
|
||||
}
|
||||
|
||||
public static String getFilesContent(Context context, String path) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try {
|
||||
String[] content = context.getAssets().list(path);
|
||||
if (content.length > 0) {
|
||||
for (String file : content) {
|
||||
if (!file.endsWith(".map")) {
|
||||
builder.append(getFilesContent(context, path + "/" + file));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return readFileFromAssets(context.getAssets(), path);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.warn("Unable to read file at path " + path);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static JSONObject createPluginHeader(PluginHandle plugin) {
|
||||
JSONObject pluginObj = new JSONObject();
|
||||
Collection<PluginMethodHandle> methods = plugin.getMethods();
|
||||
try {
|
||||
String id = plugin.getId();
|
||||
JSONArray methodArray = new JSONArray();
|
||||
pluginObj.put("name", id);
|
||||
|
||||
for (PluginMethodHandle method : methods) {
|
||||
methodArray.put(createPluginMethodHeader(method));
|
||||
}
|
||||
|
||||
pluginObj.put("methods", methodArray);
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
return pluginObj;
|
||||
}
|
||||
|
||||
private static JSONObject createPluginMethodHeader(PluginMethodHandle method) {
|
||||
JSONObject methodObj = new JSONObject();
|
||||
|
||||
try {
|
||||
methodObj.put("name", method.getName());
|
||||
if (!method.getReturnType().equals(PluginMethod.RETURN_NONE)) {
|
||||
methodObj.put("rtype", method.getReturnType());
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return methodObj;
|
||||
}
|
||||
|
||||
public static String getBridgeJS(Context context) throws JSExportException {
|
||||
return getFilesContent(context, "native-bridge.js");
|
||||
}
|
||||
|
||||
private static String generateMethodJS(PluginHandle plugin, PluginMethodHandle method) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
List<String> args = new ArrayList<>();
|
||||
// Add the catch all param that will take a full javascript object to pass to the plugin
|
||||
args.add(CATCHALL_OPTIONS_PARAM);
|
||||
|
||||
String returnType = method.getReturnType();
|
||||
if (returnType.equals(PluginMethod.RETURN_CALLBACK)) {
|
||||
args.add(CALLBACK_PARAM);
|
||||
}
|
||||
|
||||
// Create the method function declaration
|
||||
lines.add("t['" + method.getName() + "'] = function(" + TextUtils.join(", ", args) + ") {");
|
||||
|
||||
switch (returnType) {
|
||||
case PluginMethod.RETURN_NONE:
|
||||
lines.add(
|
||||
"return w.Capacitor.nativeCallback('" +
|
||||
plugin.getId() +
|
||||
"', '" +
|
||||
method.getName() +
|
||||
"', " +
|
||||
CATCHALL_OPTIONS_PARAM +
|
||||
")"
|
||||
);
|
||||
break;
|
||||
case PluginMethod.RETURN_PROMISE:
|
||||
lines.add(
|
||||
"return w.Capacitor.nativePromise('" + plugin.getId() + "', '" + method.getName() + "', " + CATCHALL_OPTIONS_PARAM + ")"
|
||||
);
|
||||
break;
|
||||
case PluginMethod.RETURN_CALLBACK:
|
||||
lines.add(
|
||||
"return w.Capacitor.nativeCallback('" +
|
||||
plugin.getId() +
|
||||
"', '" +
|
||||
method.getName() +
|
||||
"', " +
|
||||
CATCHALL_OPTIONS_PARAM +
|
||||
", " +
|
||||
CALLBACK_PARAM +
|
||||
")"
|
||||
);
|
||||
break;
|
||||
default:
|
||||
// TODO: Do something here?
|
||||
}
|
||||
|
||||
lines.add("}");
|
||||
|
||||
return TextUtils.join("\n", lines);
|
||||
}
|
||||
}
|
||||
16
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSExportException.java
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
public class JSExportException extends Exception {
|
||||
|
||||
public JSExportException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public JSExportException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public JSExportException(String s, Throwable t) {
|
||||
super(s, t);
|
||||
}
|
||||
}
|
||||
127
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSInjector.java
generated
vendored
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* JSInject is responsible for returning Capacitor's core
|
||||
* runtime JS and any plugin JS back into HTML page responses
|
||||
* to the client.
|
||||
*/
|
||||
class JSInjector {
|
||||
|
||||
private String globalJS;
|
||||
private String bridgeJS;
|
||||
private String pluginJS;
|
||||
private String cordovaJS;
|
||||
private String cordovaPluginsJS;
|
||||
private String cordovaPluginsFileJS;
|
||||
private String localUrlJS;
|
||||
private String miscJS;
|
||||
|
||||
public JSInjector(
|
||||
String globalJS,
|
||||
String bridgeJS,
|
||||
String pluginJS,
|
||||
String cordovaJS,
|
||||
String cordovaPluginsJS,
|
||||
String cordovaPluginsFileJS,
|
||||
String localUrlJS
|
||||
) {
|
||||
this(globalJS, bridgeJS, pluginJS, cordovaJS, cordovaPluginsJS, cordovaPluginsFileJS, localUrlJS, null);
|
||||
}
|
||||
|
||||
public JSInjector(
|
||||
String globalJS,
|
||||
String bridgeJS,
|
||||
String pluginJS,
|
||||
String cordovaJS,
|
||||
String cordovaPluginsJS,
|
||||
String cordovaPluginsFileJS,
|
||||
String localUrlJS,
|
||||
String miscJS
|
||||
) {
|
||||
this.globalJS = globalJS;
|
||||
this.bridgeJS = bridgeJS;
|
||||
this.pluginJS = pluginJS;
|
||||
this.cordovaJS = cordovaJS;
|
||||
this.cordovaPluginsJS = cordovaPluginsJS;
|
||||
this.cordovaPluginsFileJS = cordovaPluginsFileJS;
|
||||
this.localUrlJS = localUrlJS;
|
||||
this.miscJS = miscJS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates injectable JS content.
|
||||
* This may be used in other forms of injecting that aren't using an InputStream.
|
||||
* @return
|
||||
*/
|
||||
public String getScriptString() {
|
||||
String scriptString =
|
||||
globalJS +
|
||||
"\n\n" +
|
||||
localUrlJS +
|
||||
"\n\n" +
|
||||
bridgeJS +
|
||||
"\n\n" +
|
||||
pluginJS +
|
||||
"\n\n" +
|
||||
cordovaJS +
|
||||
"\n\n" +
|
||||
cordovaPluginsFileJS +
|
||||
"\n\n" +
|
||||
cordovaPluginsJS;
|
||||
|
||||
if (miscJS != null) {
|
||||
scriptString += "\n\n" + miscJS;
|
||||
}
|
||||
|
||||
return scriptString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an InputStream from the web server, prepend it with
|
||||
* our JS stream
|
||||
* @param responseStream
|
||||
* @return
|
||||
*/
|
||||
public InputStream getInjectedStream(InputStream responseStream) {
|
||||
String js = "<script type=\"text/javascript\">" + getScriptString() + "</script>";
|
||||
String html = this.readAssetStream(responseStream);
|
||||
|
||||
// Insert the js string at the position after <head> or before </head> using StringBuilder
|
||||
StringBuilder modifiedHtml = new StringBuilder(html);
|
||||
if (html.contains("<head>")) {
|
||||
modifiedHtml.insert(html.indexOf("<head>") + "<head>".length(), "\n" + js + "\n");
|
||||
html = modifiedHtml.toString();
|
||||
} else if (html.contains("</head>")) {
|
||||
modifiedHtml.insert(html.indexOf("</head>"), "\n" + js + "\n");
|
||||
html = modifiedHtml.toString();
|
||||
} else {
|
||||
Logger.error("Unable to inject Capacitor, Plugins won't work");
|
||||
}
|
||||
return new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private String readAssetStream(InputStream stream) {
|
||||
try {
|
||||
final int bufferSize = 1024;
|
||||
final char[] buffer = new char[bufferSize];
|
||||
final StringBuilder out = new StringBuilder();
|
||||
Reader in = new InputStreamReader(stream, StandardCharsets.UTF_8);
|
||||
for (;;) {
|
||||
int rsz = in.read(buffer, 0, buffer.length);
|
||||
if (rsz < 0) break;
|
||||
out.append(buffer, 0, rsz);
|
||||
}
|
||||
return out.toString();
|
||||
} catch (Exception e) {
|
||||
Logger.error("Unable to process HTML asset file. This is a fatal error", e);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
164
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSObject.java
generated
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* A wrapper around JSONObject that isn't afraid to do simple
|
||||
* JSON put operations without having to throw an exception
|
||||
* for every little thing jeez
|
||||
*/
|
||||
public class JSObject extends JSONObject {
|
||||
|
||||
public JSObject() {
|
||||
super();
|
||||
}
|
||||
|
||||
public JSObject(String json) throws JSONException {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public JSObject(JSONObject obj, String[] names) throws JSONException {
|
||||
super(obj, names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a pathetic JSONObject into a JSObject
|
||||
* @param obj
|
||||
*/
|
||||
public static JSObject fromJSONObject(JSONObject obj) throws JSONException {
|
||||
Iterator<String> keysIter = obj.keys();
|
||||
List<String> keys = new ArrayList<>();
|
||||
while (keysIter.hasNext()) {
|
||||
keys.add(keysIter.next());
|
||||
}
|
||||
|
||||
return new JSObject(obj, keys.toArray(new String[keys.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getString(String key) {
|
||||
return getString(key, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getString(String key, @Nullable String defaultValue) {
|
||||
try {
|
||||
String value = super.getString(key);
|
||||
if (!super.isNull(key)) {
|
||||
return value;
|
||||
}
|
||||
} catch (JSONException ex) {}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getInteger(String key) {
|
||||
return getInteger(key, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getInteger(String key, @Nullable Integer defaultValue) {
|
||||
try {
|
||||
return super.getInt(key);
|
||||
} catch (JSONException e) {}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getBoolean(String key, @Nullable Boolean defaultValue) {
|
||||
try {
|
||||
return super.getBoolean(key);
|
||||
} catch (JSONException e) {}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch boolean from jsonObject
|
||||
*/
|
||||
@Nullable
|
||||
public Boolean getBool(String key) {
|
||||
return getBoolean(key, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JSObject getJSObject(String name) {
|
||||
try {
|
||||
return getJSObject(name, null);
|
||||
} catch (JSONException e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JSObject getJSObject(String name, @Nullable JSObject defaultValue) throws JSONException {
|
||||
try {
|
||||
Object obj = get(name);
|
||||
if (obj instanceof JSONObject) {
|
||||
Iterator<String> keysIter = ((JSONObject) obj).keys();
|
||||
List<String> keys = new ArrayList<>();
|
||||
while (keysIter.hasNext()) {
|
||||
keys.add(keysIter.next());
|
||||
}
|
||||
|
||||
return new JSObject((JSONObject) obj, keys.toArray(new String[keys.size()]));
|
||||
}
|
||||
} catch (JSONException ex) {}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSObject put(String key, boolean value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSObject put(String key, int value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSObject put(String key, long value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSObject put(String key, double value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSObject put(String key, Object value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSObject put(String key, String value) {
|
||||
try {
|
||||
super.put(key, value);
|
||||
} catch (JSONException ex) {}
|
||||
return this;
|
||||
}
|
||||
|
||||
public JSObject putSafe(String key, Object value) throws JSONException {
|
||||
return (JSObject) super.put(key, value);
|
||||
}
|
||||
}
|
||||
65
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/JSValue.java
generated
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* Represents a single user-data value of any type on the capacitor PluginCall object.
|
||||
*/
|
||||
public class JSValue {
|
||||
|
||||
private final Object value;
|
||||
|
||||
/**
|
||||
* @param call The capacitor plugin call, used for accessing the value safely.
|
||||
* @param name The name of the property to access.
|
||||
*/
|
||||
public JSValue(PluginCall call, String name) {
|
||||
this.value = this.toValue(call, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the coerced but uncasted underlying value.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getValue().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying value as a JSObject, or throwing if it cannot.
|
||||
*
|
||||
* @throws JSONException If the underlying value is not a JSObject.
|
||||
*/
|
||||
public JSObject toJSObject() throws JSONException {
|
||||
if (this.value instanceof JSObject) return (JSObject) this.value;
|
||||
throw new JSONException("JSValue could not be coerced to JSObject.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying value as a JSArray, or throwing if it cannot.
|
||||
*
|
||||
* @throws JSONException If the underlying value is not a JSArray.
|
||||
*/
|
||||
public JSArray toJSArray() throws JSONException {
|
||||
if (this.value instanceof JSArray) return (JSArray) this.value;
|
||||
throw new JSONException("JSValue could not be coerced to JSArray.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying value this object represents, coercing it into a capacitor-friendly object if supported.
|
||||
*/
|
||||
private Object toValue(PluginCall call, String name) {
|
||||
Object value = null;
|
||||
value = call.getArray(name, null);
|
||||
if (value != null) return value;
|
||||
value = call.getObject(name, null);
|
||||
if (value != null) return value;
|
||||
value = call.getString(name, null);
|
||||
if (value != null) return value;
|
||||
return call.getData().opt(name);
|
||||
}
|
||||
}
|
||||
103
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Logger.java
generated
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
public class Logger {
|
||||
|
||||
public static final String LOG_TAG_CORE = "Capacitor";
|
||||
public static CapConfig config;
|
||||
|
||||
private static Logger instance;
|
||||
|
||||
private static Logger getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Logger();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void init(CapConfig config) {
|
||||
Logger.getInstance().loadConfig(config);
|
||||
}
|
||||
|
||||
private void loadConfig(CapConfig config) {
|
||||
Logger.config = config;
|
||||
}
|
||||
|
||||
public static String tags(String... subtags) {
|
||||
if (subtags != null && subtags.length > 0) {
|
||||
return LOG_TAG_CORE + "/" + TextUtils.join("/", subtags);
|
||||
}
|
||||
|
||||
return LOG_TAG_CORE;
|
||||
}
|
||||
|
||||
public static void verbose(String message) {
|
||||
verbose(LOG_TAG_CORE, message);
|
||||
}
|
||||
|
||||
public static void verbose(String tag, String message) {
|
||||
if (!shouldLog()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.v(tag, message);
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
debug(LOG_TAG_CORE, message);
|
||||
}
|
||||
|
||||
public static void debug(String tag, String message) {
|
||||
if (!shouldLog()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(tag, message);
|
||||
}
|
||||
|
||||
public static void info(String message) {
|
||||
info(LOG_TAG_CORE, message);
|
||||
}
|
||||
|
||||
public static void info(String tag, String message) {
|
||||
if (!shouldLog()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(tag, message);
|
||||
}
|
||||
|
||||
public static void warn(String message) {
|
||||
warn(LOG_TAG_CORE, message);
|
||||
}
|
||||
|
||||
public static void warn(String tag, String message) {
|
||||
if (!shouldLog()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.w(tag, message);
|
||||
}
|
||||
|
||||
public static void error(String message) {
|
||||
error(LOG_TAG_CORE, message, null);
|
||||
}
|
||||
|
||||
public static void error(String message, Throwable e) {
|
||||
error(LOG_TAG_CORE, message, e);
|
||||
}
|
||||
|
||||
public static void error(String tag, String message, Throwable e) {
|
||||
if (!shouldLog()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.e(tag, message, e);
|
||||
}
|
||||
|
||||
public static boolean shouldLog() {
|
||||
return config == null || config.isLoggingEnabled();
|
||||
}
|
||||
}
|
||||
157
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/MessageHandler.java
generated
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.WebView;
|
||||
import androidx.webkit.JavaScriptReplyProxy;
|
||||
import androidx.webkit.WebViewCompat;
|
||||
import androidx.webkit.WebViewFeature;
|
||||
import org.apache.cordova.PluginManager;
|
||||
|
||||
/**
|
||||
* MessageHandler handles messages from the WebView, dispatching them
|
||||
* to plugins.
|
||||
*/
|
||||
public class MessageHandler {
|
||||
|
||||
private Bridge bridge;
|
||||
private WebView webView;
|
||||
private PluginManager cordovaPluginManager;
|
||||
private JavaScriptReplyProxy javaScriptReplyProxy;
|
||||
|
||||
public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
|
||||
this.bridge = bridge;
|
||||
this.webView = webView;
|
||||
this.cordovaPluginManager = cordovaPluginManager;
|
||||
|
||||
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && !bridge.getConfig().isUsingLegacyBridge()) {
|
||||
WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
|
||||
if (isMainFrame) {
|
||||
postMessage(message.getData());
|
||||
javaScriptReplyProxy = replyProxy;
|
||||
} else {
|
||||
Logger.warn("Plugin execution is allowed in Main Frame only");
|
||||
}
|
||||
};
|
||||
try {
|
||||
WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener);
|
||||
} catch (Exception ex) {
|
||||
webView.addJavascriptInterface(this, "androidBridge");
|
||||
}
|
||||
} else {
|
||||
webView.addJavascriptInterface(this, "androidBridge");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main message handler that will be called from JavaScript
|
||||
* to send a message to the native bridge.
|
||||
* @param jsonStr
|
||||
*/
|
||||
@JavascriptInterface
|
||||
@SuppressWarnings("unused")
|
||||
public void postMessage(String jsonStr) {
|
||||
try {
|
||||
JSObject postData = new JSObject(jsonStr);
|
||||
|
||||
String type = postData.getString("type");
|
||||
|
||||
boolean typeIsNotNull = type != null;
|
||||
boolean isCordovaPlugin = typeIsNotNull && type.equals("cordova");
|
||||
boolean isJavaScriptError = typeIsNotNull && type.equals("js.error");
|
||||
|
||||
String callbackId = postData.getString("callbackId");
|
||||
|
||||
if (isCordovaPlugin) {
|
||||
String service = postData.getString("service");
|
||||
String action = postData.getString("action");
|
||||
String actionArgs = postData.getString("actionArgs");
|
||||
|
||||
Logger.verbose(
|
||||
Logger.tags("Plugin"),
|
||||
"To native (Cordova plugin): callbackId: " +
|
||||
callbackId +
|
||||
", service: " +
|
||||
service +
|
||||
", action: " +
|
||||
action +
|
||||
", actionArgs: " +
|
||||
actionArgs
|
||||
);
|
||||
|
||||
this.callCordovaPluginMethod(callbackId, service, action, actionArgs);
|
||||
} else if (isJavaScriptError) {
|
||||
Logger.error("JavaScript Error: " + jsonStr);
|
||||
} else {
|
||||
String pluginId = postData.getString("pluginId");
|
||||
String methodName = postData.getString("methodName");
|
||||
JSObject methodData = postData.getJSObject("options", new JSObject());
|
||||
|
||||
Logger.verbose(
|
||||
Logger.tags("Plugin"),
|
||||
"To native (Capacitor plugin): callbackId: " + callbackId + ", pluginId: " + pluginId + ", methodName: " + methodName
|
||||
);
|
||||
|
||||
this.callPluginMethod(callbackId, pluginId, methodName, methodData);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.error("Post message error:", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendResponseMessage(PluginCall call, PluginResult successResult, PluginResult errorResult) {
|
||||
try {
|
||||
PluginResult data = new PluginResult();
|
||||
data.put("save", call.isKeptAlive());
|
||||
data.put("callbackId", call.getCallbackId());
|
||||
data.put("pluginId", call.getPluginId());
|
||||
data.put("methodName", call.getMethodName());
|
||||
|
||||
boolean pluginResultInError = errorResult != null;
|
||||
if (pluginResultInError) {
|
||||
data.put("success", false);
|
||||
data.put("error", errorResult);
|
||||
Logger.debug("Sending plugin error: " + data.toString());
|
||||
} else {
|
||||
data.put("success", true);
|
||||
if (successResult != null) {
|
||||
data.put("data", successResult);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isValidCallbackId = !call.getCallbackId().equals(PluginCall.CALLBACK_ID_DANGLING);
|
||||
if (isValidCallbackId) {
|
||||
if (bridge.getConfig().isUsingLegacyBridge()) {
|
||||
legacySendResponseMessage(data);
|
||||
} else if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && javaScriptReplyProxy != null) {
|
||||
javaScriptReplyProxy.postMessage(data.toString());
|
||||
} else {
|
||||
legacySendResponseMessage(data);
|
||||
}
|
||||
} else {
|
||||
bridge.getApp().fireRestoredResult(data);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.error("sendResponseMessage: error: " + ex);
|
||||
}
|
||||
if (!call.isKeptAlive()) {
|
||||
call.release(bridge);
|
||||
}
|
||||
}
|
||||
|
||||
private void legacySendResponseMessage(PluginResult data) {
|
||||
final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";
|
||||
final WebView webView = this.webView;
|
||||
webView.post(() -> webView.evaluateJavascript(runScript, null));
|
||||
}
|
||||
|
||||
private void callPluginMethod(String callbackId, String pluginId, String methodName, JSObject methodData) {
|
||||
PluginCall call = new PluginCall(this, pluginId, callbackId, methodName, methodData);
|
||||
bridge.callPluginMethod(pluginId, methodName, call);
|
||||
}
|
||||
|
||||
private void callCordovaPluginMethod(String callbackId, String service, String action, String actionArgs) {
|
||||
bridge.execute(() -> {
|
||||
cordovaPluginManager.exec(service, action, callbackId, actionArgs);
|
||||
});
|
||||
}
|
||||
}
|
||||
37
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/NativePlugin.java
generated
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Base annotation for all Plugins
|
||||
* @deprecated
|
||||
* <p> Use {@link CapacitorPlugin} instead
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Deprecated
|
||||
public @interface NativePlugin {
|
||||
/**
|
||||
* Request codes this plugin uses and responds to, in order to tie
|
||||
* Android events back the plugin to handle
|
||||
*/
|
||||
int[] requestCodes() default {};
|
||||
|
||||
/**
|
||||
* Permissions this plugin needs, in order to make permission requests
|
||||
* easy if the plugin only needs basic permission prompting
|
||||
*/
|
||||
String[] permissions() default {};
|
||||
|
||||
/**
|
||||
* The request code to use when automatically requesting permissions
|
||||
*/
|
||||
int permissionRequestCode() default 9000;
|
||||
|
||||
/**
|
||||
* A custom name for the plugin, otherwise uses the
|
||||
* simple class name.
|
||||
*/
|
||||
String name() default "";
|
||||
}
|
||||
31
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PermissionState.java
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Represents the state of a permission
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public enum PermissionState {
|
||||
GRANTED("granted"),
|
||||
DENIED("denied"),
|
||||
PROMPT("prompt"),
|
||||
PROMPT_WITH_RATIONALE("prompt-with-rationale");
|
||||
|
||||
private String state;
|
||||
|
||||
PermissionState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public static PermissionState byState(String state) {
|
||||
state = state.toUpperCase(Locale.ROOT).replace('-', '_');
|
||||
return valueOf(state);
|
||||
}
|
||||
}
|
||||
1050
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/Plugin.java
generated
vendored
Normal file
394
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginCall.java
generated
vendored
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Wraps a call from the web layer to native
|
||||
*/
|
||||
public class PluginCall {
|
||||
|
||||
/**
|
||||
* A special callback id that indicates there is no matching callback
|
||||
* on the client to associate any PluginCall results back to. This is used
|
||||
* in the case of an app resuming with saved instance data, for example.
|
||||
*/
|
||||
public static final String CALLBACK_ID_DANGLING = "-1";
|
||||
|
||||
private final MessageHandler msgHandler;
|
||||
private final String pluginId;
|
||||
private final String callbackId;
|
||||
private final String methodName;
|
||||
private final JSObject data;
|
||||
|
||||
private boolean keepAlive = false;
|
||||
|
||||
/**
|
||||
* Indicates that this PluginCall was released, and should no longer be used
|
||||
*/
|
||||
@Deprecated
|
||||
private boolean isReleased = false;
|
||||
|
||||
public PluginCall(MessageHandler msgHandler, String pluginId, String callbackId, String methodName, JSObject data) {
|
||||
this.msgHandler = msgHandler;
|
||||
this.pluginId = pluginId;
|
||||
this.callbackId = callbackId;
|
||||
this.methodName = methodName;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void successCallback(PluginResult successResult) {
|
||||
if (CALLBACK_ID_DANGLING.equals(this.callbackId)) {
|
||||
// don't send back response if the callbackId was "-1"
|
||||
return;
|
||||
}
|
||||
|
||||
this.msgHandler.sendResponseMessage(this, successResult, null);
|
||||
}
|
||||
|
||||
public void resolve(JSObject data) {
|
||||
PluginResult result = new PluginResult(data);
|
||||
this.msgHandler.sendResponseMessage(this, result, null);
|
||||
}
|
||||
|
||||
public void resolve() {
|
||||
this.msgHandler.sendResponseMessage(this, null, null);
|
||||
}
|
||||
|
||||
public void errorCallback(String msg) {
|
||||
PluginResult errorResult = new PluginResult();
|
||||
|
||||
try {
|
||||
errorResult.put("message", msg);
|
||||
} catch (Exception jsonEx) {
|
||||
Logger.error(Logger.tags("Plugin"), jsonEx.toString(), null);
|
||||
}
|
||||
|
||||
this.msgHandler.sendResponseMessage(this, null, errorResult);
|
||||
}
|
||||
|
||||
public void reject(String msg, String code, Exception ex, JSObject data) {
|
||||
PluginResult errorResult = new PluginResult();
|
||||
|
||||
if (ex != null) {
|
||||
Logger.error(Logger.tags("Plugin"), msg, ex);
|
||||
}
|
||||
|
||||
try {
|
||||
errorResult.put("message", msg);
|
||||
errorResult.put("code", code);
|
||||
if (null != data) {
|
||||
errorResult.put("data", data);
|
||||
}
|
||||
} catch (Exception jsonEx) {
|
||||
Logger.error(Logger.tags("Plugin"), jsonEx.getMessage(), jsonEx);
|
||||
}
|
||||
|
||||
this.msgHandler.sendResponseMessage(this, null, errorResult);
|
||||
}
|
||||
|
||||
public void reject(String msg, Exception ex, JSObject data) {
|
||||
reject(msg, null, ex, data);
|
||||
}
|
||||
|
||||
public void reject(String msg, String code, JSObject data) {
|
||||
reject(msg, code, null, data);
|
||||
}
|
||||
|
||||
public void reject(String msg, String code, Exception ex) {
|
||||
reject(msg, code, ex, null);
|
||||
}
|
||||
|
||||
public void reject(String msg, JSObject data) {
|
||||
reject(msg, null, null, data);
|
||||
}
|
||||
|
||||
public void reject(String msg, Exception ex) {
|
||||
reject(msg, null, ex, null);
|
||||
}
|
||||
|
||||
public void reject(String msg, String code) {
|
||||
reject(msg, code, null, null);
|
||||
}
|
||||
|
||||
public void reject(String msg) {
|
||||
reject(msg, null, null, null);
|
||||
}
|
||||
|
||||
public void unimplemented() {
|
||||
unimplemented("not implemented");
|
||||
}
|
||||
|
||||
public void unimplemented(String msg) {
|
||||
reject(msg, "UNIMPLEMENTED", null, null);
|
||||
}
|
||||
|
||||
public void unavailable() {
|
||||
unavailable("not available");
|
||||
}
|
||||
|
||||
public void unavailable(String msg) {
|
||||
reject(msg, "UNAVAILABLE", null, null);
|
||||
}
|
||||
|
||||
public String getPluginId() {
|
||||
return this.pluginId;
|
||||
}
|
||||
|
||||
public String getCallbackId() {
|
||||
return this.callbackId;
|
||||
}
|
||||
|
||||
public String getMethodName() {
|
||||
return this.methodName;
|
||||
}
|
||||
|
||||
public JSObject getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getString(String name) {
|
||||
return this.getString(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getString(String name, @Nullable String defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getInt(String name) {
|
||||
return this.getInt(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getInt(String name, @Nullable Integer defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof Integer) {
|
||||
return (Integer) value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getLong(String name) {
|
||||
return this.getLong(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Long getLong(String name, @Nullable Long defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getFloat(String name) {
|
||||
return this.getFloat(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getFloat(String name, @Nullable Float defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof Float) {
|
||||
return (Float) value;
|
||||
}
|
||||
if (value instanceof Double) {
|
||||
return ((Double) value).floatValue();
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return ((Integer) value).floatValue();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getDouble(String name) {
|
||||
return this.getDouble(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Double getDouble(String name, @Nullable Double defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof Double) {
|
||||
return (Double) value;
|
||||
}
|
||||
if (value instanceof Float) {
|
||||
return ((Float) value).doubleValue();
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
return ((Integer) value).doubleValue();
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getBoolean(String name) {
|
||||
return this.getBoolean(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Boolean getBoolean(String name, @Nullable Boolean defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public JSObject getObject(String name) {
|
||||
return this.getObject(name, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public JSObject getObject(String name, JSObject defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof JSONObject) {
|
||||
try {
|
||||
return JSObject.fromJSONObject((JSONObject) value);
|
||||
} catch (JSONException ex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public JSArray getArray(String name) {
|
||||
return this.getArray(name, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSONArray and turn it into a JSArray
|
||||
* @param name
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public JSArray getArray(String name, JSArray defaultValue) {
|
||||
Object value = this.data.opt(name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (value instanceof JSONArray) {
|
||||
try {
|
||||
JSONArray valueArray = (JSONArray) value;
|
||||
List<Object> items = new ArrayList<>();
|
||||
for (int i = 0; i < valueArray.length(); i++) {
|
||||
items.add(valueArray.get(i));
|
||||
}
|
||||
return new JSArray(items.toArray());
|
||||
} catch (JSONException ex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name of the option to check
|
||||
* @return boolean indicating if the plugin call has an option for the provided name.
|
||||
* @deprecated Presence of a key should not be considered significant.
|
||||
* Use typed accessors to check the value instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean hasOption(String name) {
|
||||
return this.data.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the Bridge should cache this call in order to call
|
||||
* it again later. For example, the addListener system uses this to
|
||||
* continuously call the call's callback (😆).
|
||||
* @deprecated use {@link #setKeepAlive(Boolean)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void save() {
|
||||
setKeepAlive(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the Bridge should cache this call in order to call
|
||||
* it again later. For example, the addListener system uses this to
|
||||
* continuously call the call's callback.
|
||||
*
|
||||
* @param keepAlive whether to keep the callback saved
|
||||
*/
|
||||
public void setKeepAlive(Boolean keepAlive) {
|
||||
this.keepAlive = keepAlive;
|
||||
}
|
||||
|
||||
public void release(Bridge bridge) {
|
||||
this.keepAlive = false;
|
||||
bridge.releaseCall(this);
|
||||
this.isReleased = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #isKeptAlive()}
|
||||
* @return true if the plugin call is kept alive
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isSaved() {
|
||||
return isKeptAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the keepAlive value of the plugin call
|
||||
* @return true if the plugin call is kept alive
|
||||
*/
|
||||
public boolean isKeptAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean isReleased() {
|
||||
return isReleased;
|
||||
}
|
||||
|
||||
class PluginCallDataTypeException extends Exception {
|
||||
|
||||
PluginCallDataTypeException(String m) {
|
||||
super(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
116
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginConfig.java
generated
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import com.getcapacitor.util.JSONUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Represents the configuration options for plugins used by Capacitor
|
||||
*/
|
||||
public class PluginConfig {
|
||||
|
||||
/**
|
||||
* The object containing plugin config values.
|
||||
*/
|
||||
private final JSONObject config;
|
||||
|
||||
/**
|
||||
* Constructs a PluginsConfig with the provided JSONObject value.
|
||||
*
|
||||
* @param config A plugin configuration expressed as a JSON Object
|
||||
*/
|
||||
PluginConfig(JSONObject config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
public String getString(String configKey) {
|
||||
return getString(configKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
public String getString(String configKey, String defaultValue) {
|
||||
return JSONUtils.getString(config, configKey, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a boolean value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
public boolean getBoolean(String configKey, boolean defaultValue) {
|
||||
return JSONUtils.getBoolean(config, configKey, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an integer value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
public int getInt(String configKey, int defaultValue) {
|
||||
return JSONUtils.getInt(config, configKey, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string array value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
public String[] getArray(String configKey) {
|
||||
return getArray(configKey, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a string array value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @param defaultValue A default value to return if the key does not exist in the config
|
||||
* @return The value from the config, if key exists. Default value returned if not
|
||||
*/
|
||||
public String[] getArray(String configKey, String[] defaultValue) {
|
||||
return JSONUtils.getArray(config, configKey, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a JSON object value for a plugin in the Capacitor config.
|
||||
*
|
||||
* @param configKey The key of the value to retrieve
|
||||
* @return The value from the config, if exists. Null if not
|
||||
*/
|
||||
public JSONObject getObject(String configKey) {
|
||||
return JSONUtils.getObject(config, configKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the PluginConfig is empty.
|
||||
*
|
||||
* @return true if the plugin config has no entries
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return config.length() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JSON Object containing the config of the the provided plugin ID.
|
||||
*
|
||||
* @return The config for that plugin
|
||||
*/
|
||||
public JSONObject getConfigJSON() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
160
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginHandle.java
generated
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* PluginHandle is an instance of a plugin that has been registered
|
||||
* and indexed. Think of it as a Plugin instance with extra metadata goodies
|
||||
*/
|
||||
public class PluginHandle {
|
||||
|
||||
private final Bridge bridge;
|
||||
private final Class<? extends Plugin> pluginClass;
|
||||
|
||||
private final Map<String, PluginMethodHandle> pluginMethods = new HashMap<>();
|
||||
|
||||
private final String pluginId;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private NativePlugin legacyPluginAnnotation;
|
||||
|
||||
private CapacitorPlugin pluginAnnotation;
|
||||
|
||||
private Plugin instance;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private PluginHandle(Class<? extends Plugin> clazz, Bridge bridge) throws InvalidPluginException {
|
||||
this.bridge = bridge;
|
||||
this.pluginClass = clazz;
|
||||
|
||||
CapacitorPlugin pluginAnnotation = pluginClass.getAnnotation(CapacitorPlugin.class);
|
||||
if (pluginAnnotation == null) {
|
||||
// Check for legacy plugin annotation, @NativePlugin
|
||||
NativePlugin legacyPluginAnnotation = pluginClass.getAnnotation(NativePlugin.class);
|
||||
if (legacyPluginAnnotation == null) {
|
||||
throw new InvalidPluginException("No @CapacitorPlugin annotation found for plugin " + pluginClass.getName());
|
||||
}
|
||||
|
||||
if (!legacyPluginAnnotation.name().equals("")) {
|
||||
this.pluginId = legacyPluginAnnotation.name();
|
||||
} else {
|
||||
this.pluginId = pluginClass.getSimpleName();
|
||||
}
|
||||
|
||||
this.legacyPluginAnnotation = legacyPluginAnnotation;
|
||||
} else {
|
||||
if (!pluginAnnotation.name().equals("")) {
|
||||
this.pluginId = pluginAnnotation.name();
|
||||
} else {
|
||||
this.pluginId = pluginClass.getSimpleName();
|
||||
}
|
||||
|
||||
this.pluginAnnotation = pluginAnnotation;
|
||||
}
|
||||
|
||||
this.indexMethods(clazz);
|
||||
}
|
||||
|
||||
public PluginHandle(Bridge bridge, Class<? extends Plugin> pluginClass) throws InvalidPluginException, PluginLoadException {
|
||||
this(pluginClass, bridge);
|
||||
this.load();
|
||||
}
|
||||
|
||||
public PluginHandle(Bridge bridge, Plugin plugin) throws InvalidPluginException {
|
||||
this(plugin.getClass(), bridge);
|
||||
this.loadInstance(plugin);
|
||||
}
|
||||
|
||||
public Class<? extends Plugin> getPluginClass() {
|
||||
return pluginClass;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.pluginId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public NativePlugin getLegacyPluginAnnotation() {
|
||||
return this.legacyPluginAnnotation;
|
||||
}
|
||||
|
||||
public CapacitorPlugin getPluginAnnotation() {
|
||||
return this.pluginAnnotation;
|
||||
}
|
||||
|
||||
public Plugin getInstance() {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
public Collection<PluginMethodHandle> getMethods() {
|
||||
return this.pluginMethods.values();
|
||||
}
|
||||
|
||||
public Plugin load() throws PluginLoadException {
|
||||
if (this.instance != null) {
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
try {
|
||||
this.instance = this.pluginClass.getDeclaredConstructor().newInstance();
|
||||
return this.loadInstance(instance);
|
||||
} catch (Exception ex) {
|
||||
throw new PluginLoadException("Unable to load plugin instance. Ensure plugin is publicly accessible");
|
||||
}
|
||||
}
|
||||
|
||||
public Plugin loadInstance(Plugin plugin) {
|
||||
this.instance = plugin;
|
||||
this.instance.setPluginHandle(this);
|
||||
this.instance.setBridge(this.bridge);
|
||||
this.instance.load();
|
||||
this.instance.initializeActivityLaunchers();
|
||||
return this.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a method on a plugin.
|
||||
* @param methodName the name of the method to call
|
||||
* @param call the constructed PluginCall with parameters from the caller
|
||||
* @throws InvalidPluginMethodException if no method was found on that plugin
|
||||
*/
|
||||
public void invoke(String methodName, PluginCall call)
|
||||
throws PluginLoadException, InvalidPluginMethodException, InvocationTargetException, IllegalAccessException {
|
||||
if (this.instance == null) {
|
||||
// Can throw PluginLoadException
|
||||
this.load();
|
||||
}
|
||||
|
||||
PluginMethodHandle methodMeta = pluginMethods.get(methodName);
|
||||
if (methodMeta == null) {
|
||||
throw new InvalidPluginMethodException("No method " + methodName + " found for plugin " + pluginClass.getName());
|
||||
}
|
||||
|
||||
methodMeta.getMethod().invoke(this.instance, call);
|
||||
}
|
||||
|
||||
/**
|
||||
* Index all the known callable methods for a plugin for faster
|
||||
* invocation later
|
||||
*/
|
||||
private void indexMethods(Class<? extends Plugin> plugin) {
|
||||
//Method[] methods = pluginClass.getDeclaredMethods();
|
||||
Method[] methods = pluginClass.getMethods();
|
||||
|
||||
for (Method methodReflect : methods) {
|
||||
PluginMethod method = methodReflect.getAnnotation(PluginMethod.class);
|
||||
|
||||
if (method == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PluginMethodHandle methodMeta = new PluginMethodHandle(methodReflect, method);
|
||||
pluginMethods.put(methodReflect.getName(), methodMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
node_modules/@capacitor/android/capacitor/src/main/java/com/getcapacitor/PluginInvocationException.java
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package com.getcapacitor;
|
||||
|
||||
class PluginInvocationException extends Exception {
|
||||
|
||||
public PluginInvocationException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public PluginInvocationException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public PluginInvocationException(String s, Throwable t) {
|
||||
super(s, t);
|
||||
}
|
||||
}
|
||||