added platforms to gitignore

This commit is contained in:
vishnuraghavb 2020-12-30 17:30:52 +05:30
parent ced01b5152
commit 9bd0d63162
5486 changed files with 4 additions and 292943 deletions

View file

@ -20,17 +20,12 @@ android {
applicationId 'com.vishnuraghav.enrecipes'
minSdkVersion 21
generatedDensities = []
// ndk {
// abiFilters.clear()
// abiFilters.addAll(['x86','armeabi-v7a','arm64-v8a'])
// }
ndk {
abiFilters.clear()
abiFilters.addAll(['arm64-v8a', 'armeabi-v7a', 'x86'])
}
}
aaptOptions {
additionalParameters "--no-version-vectors"
}
// bundle {
// language {
// enableSplit = false
// }
// }
}

View file

@ -1,2 +0,0 @@
#Wed Dec 30 13:12:10 IST 2020
gradle.version=6.4

View file

@ -1,82 +0,0 @@
{
"@nativescript-community/ui-material-button": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/include.gradle": "aa9556ead0428a00cf38da660884c16334afaf04",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button.xml": "3af1596c168b216b5554cce0a5785ecedda84fc1",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_flat.xml": "416b334bc8a4c74dd2f85996c1fc29a7f3f7423d",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_flat_icon.xml": "f20b2f5879c767a84e64609c8a98a217c4d35faf",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_icon.xml": "459d986fcaa1c27d789fb89fac5b90be23f7940d",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_outline.xml": "e2b838c88048616006216e1d89ce324a0c14a7d7",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_outline_icon.xml": "a4699f1a2a65d184638233714b95d45b0c26fb07",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_text.xml": "11f39271e457bdbe466454e6d2b321aa590c58df",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/layout/material_button_text_icon.xml": "221d0ee71b569721b2f9ebae01beecad8c4b3802",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/res/values/materialbuttonstyles.xml": "8a1f523878b2ad3ec92c3df5c69ed86e6bee5a24",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-button/platforms/android/ui_material_button.aar": "8f1cf1ee77462d7806909cfddac8412547ec5433"
},
"@nativescript/core": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript/core/platforms/android/native-api-usage.json": "34ee0e9771ad7dd9d388c191734d71507a04565a",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript/core/platforms/android/widgets-release.aar": "ea387e7a96a4ccb0df5c645b313c5dcf8042a0bb"
},
"@nativescript/social-share": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript/social-share/platforms/android/AndroidManifest.xml": "ca6e2ceca22448641563fa6f6c773ef10b292e10",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript/social-share/platforms/android/res/xml/provider_paths.xml": "dbe562dfa44616ea40d88a3cbd74b3e8f44c54f3"
},
"@nativescript/zip": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript/zip/platforms/android/include.gradle": "81c5f85b571d2665da42be015e2d1dfd271ee4e6"
},
"nativescript-couchbase-plugin": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-couchbase-plugin/platforms/android/fancycouchbase-release.aar": "498e1ee2405bdf6a35cd5f0402b2b279205f53d9",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-couchbase-plugin/platforms/android/include.gradle": "697825ccd0e49caa429d63214894357437919716"
},
"nativescript-feedback": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-feedback/platforms/android/include.gradle": "162f973f93b517e2be13dfabf0a4c6d6d0020aac",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-feedback/platforms/android/nativescript_feedback.aar": "6bb6b05373f74debd4f7fb0f47794a240794cc40"
},
"nativescript-imagecropper": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-imagecropper/platforms/android/AndroidManifest.xml": "de9e14f14dae0473e1f887952a39df5e32951275",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-imagecropper/platforms/android/include.gradle": "61ad278ee80be73a906afb5eddd2126c585ba549",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-imagecropper/platforms/android/nativescript_imagecropper.aar": "1cbfff3087414762c1785e5bbfccd593bc3331e2"
},
"nativescript-plugin-filepicker": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-plugin-filepicker/platforms/android/README.md": "45f2f63427be0a461a7e2dfd5ff0ad5bab64068f",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-plugin-filepicker/platforms/android/nativescript_plugin_filepicker.aar": "e53441dd997d4849f45247b4b4eda20fac860b5d",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-plugin-filepicker/platforms/android/include.gradle": "06e7e1be49eb6d614094596003280aa7eea789f3"
},
"nativescript-ui-calendar": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-calendar/platforms/android/typings/calendar.d.ts": "6e196553478b7d7fbe92645b60d0ac7bfa5339db",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-calendar/platforms/android/TNSCalendar-release.aar": "7c0dd1f9120ddeae8c09c2b03423889c1250f541"
},
"nativescript-ui-listview": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-listview/platforms/android/include.gradle": "47ffe675113a982585b2386750b2d4305b66b6ca",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-listview/platforms/android/typings/listview.d.ts": "d3b76f21820076bdd93468055d6da69e9b41d98e",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-listview/platforms/android/TNSListView-release.aar": "e9677c69bc3e7fa63aee988efe824a992c1fc0ab"
},
"nativescript-ui-sidedrawer": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-sidedrawer/platforms/android/TNSSideDrawer-release.aar": "ae03340e741bdf430de4849d4dd117bf07197851",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-sidedrawer/platforms/android/typings/sidedrawer.d.ts": "8256a2295125597755fe6a6faee866b0750e65f2"
},
"nativescript-vibrate": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-vibrate/platforms/android/README.md": "45f2f63427be0a461a7e2dfd5ff0ad5bab64068f",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-vibrate/platforms/android/include.gradle": "06e7e1be49eb6d614094596003280aa7eea789f3",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-vibrate/platforms/android/nativescript_vibrate.aar": "a60d480c8553e72412f49655a113759fe3321ccb"
},
"@nativescript-community/ui-material-core": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-core/platforms/android/AndroidManifest.xml": "9b6f49aa9c71e8a45ec570027e025274ffcadc96",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-core/platforms/android/include.gradle": "ec90dc697edab3c184ec95b0a42c9f206900f048",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-core/platforms/android/java/com/nativescript/material/core/Utils.java": "3813226945705be3d52cf19dc945ea9bf2c77e12",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-core/platforms/android/res/layout/material_page.xml": "29f912255e893697d6abd438f67a854149136292",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/ui-material-core/platforms/android/ui_material_core.aar": "16ba6c7b1ca76423844a6e8a94bdbeed395c1432"
},
"@nativescript-community/text": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/AndroidManifest.xml": "b80912f909195692d3bd071566274feba0b37660",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/java/com/nativescript/text/CustomTypefaceSpan.java": "421f984280aa806183057f2ddd53febdbc32d2b1",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/java/com/nativescript/text/CustomBackgroundSpan.java": "ae9e0e6d699e669f96ed7042f2145a1ab0bf6727",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/java/com/nativescript/text/Font.java": "fb4d246ad367d178e11ef08c34ec182418d30890",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/java/com/nativescript/text/HtmlToSpannedConverter.java": "38643430e4b8cac690b89a07adc3a86f7060f93d",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/java/com/nativescript/text/URLSpanNoUnderline.java": "b3da85c1d16eff30c54fb5725e1e46fea265d7ce",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/@nativescript-community/text/platforms/android/text.aar": "77d471b2127e5f1f2b78b89656e7287bcf488b22"
},
"nativescript-ui-core": {
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-core/platforms/android/typings/core.d.ts": "5c032652edfa1719ef8c8190fc0f66d3b1c313c2",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/node_modules/nativescript-ui-core/platforms/android/TNSCore-release.aar": "0e2fe0b867821ad56b8f0b9c8ac4c90f4c399e3c"
}
}

View file

@ -1,7 +0,0 @@
{
"time": "Wed Dec 30 2020 14:50:17 GMT+0530 (India Standard Time)",
"nativePlatformStatus": "3",
"changesRequireBuild": true,
"projectFileHash": "de8936b04a8811e04d93e9717fc4448bf88e2e84157623dd6556d8a57dadf3a1",
"changesRequireBuildTime": "Wed Dec 30 2020 14:50:17 GMT+0530 (India Standard Time)"
}

View file

@ -1,983 +0,0 @@
/*
* Script builds apk in release or debug mode
* To run:
* gradle assembleRelease -Prelease (release mode)
* gradle assembleDebug (debug mode -> default)
* Options:
* -Prelease //this flag will run build in release mode
* -PksPath=[path_to_keystore_file]
* -PksPassword=[password_for_keystore_file]
* -Palias=[alias_to_use_from_keystore_file]
* -Ppassword=[password_for_alias]
*
* -PtargetSdk=[target_sdk]
* -PbuildToolsVersion=[build_tools_version]
* -PcompileSdk=[compile_sdk_version]
* -PandroidXLegacy=[androidx_legacy_version]
* -PandroidXAppCompat=[androidx_appcompat_version]
* -PandroidXMaterial=[androidx_material_version]
* -PappPath=[app_path]
* -PappResourcesPath=[app_resources_path]
*/
import groovy.io.FileType
import groovy.json.JsonSlurper
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.security.MessageDigest
import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.internal.logging.text.StyledTextOutput.Style
apply plugin: "com.android.application"
apply from: "gradle-helpers/BuildToolTask.gradle"
apply from: "gradle-helpers/CustomExecutionLogger.gradle"
apply from: "gradle-helpers/AnalyticsCollector.gradle"
def enableKotlin = (project.hasProperty("useKotlin") && project.useKotlin == "true")
if (enableKotlin) {
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
}
def onlyX86 = project.hasProperty("onlyX86")
if (onlyX86) {
outLogger.withStyle(Style.Info).println "OnlyX86 build triggered."
}
//common
def BUILD_TOOLS_PATH = "$rootDir/build-tools"
def PASSED_TYPINGS_PATH = System.getenv("TNS_TYPESCRIPT_DECLARATIONS_PATH")
def TYPINGS_PATH = "$BUILD_TOOLS_PATH/typings"
if (PASSED_TYPINGS_PATH != null) {
TYPINGS_PATH = PASSED_TYPINGS_PATH
}
def PACKAGE_JSON = "package.json"
//static binding generator
def SBG_JAVA_DEPENDENCIES = "sbg-java-dependencies.txt"
def SBG_INPUT_FILE = "sbg-input-file.txt"
def SBG_OUTPUT_FILE = "sbg-output-file.txt"
def SBG_JS_PARSED_FILES = "sbg-js-parsed-files.txt"
def SBG_BINDINGS_NAME = "sbg-bindings.txt"
def SBG_INTERFACE_NAMES = "sbg-interface-names.txt"
def INPUT_JS_DIR = "$projectDir/src/main/assets/app"
def OUTPUT_JAVA_DIR = "$projectDir/src/main/java"
//metadata generator
def MDG_OUTPUT_DIR = "mdg-output-dir.txt"
def MDG_JAVA_DEPENDENCIES = "mdg-java-dependencies.txt"
def METADATA_OUT_PATH = "$projectDir/src/main/assets/metadata"
// paths to jar libraries
def pluginsJarLibraries = new LinkedList<String>()
def allJarLibraries = new LinkedList<String>()
def computeKotlinVersion = { -> project.hasProperty("kotlinVersion") ? kotlinVersion : "1.3.41" }
def computeCompileSdkVersion = { -> project.hasProperty("compileSdk") ? compileSdk : 29 }
def computeTargetSdkVersion = { -> project.hasProperty("targetSdk") ? targetSdk : 29 }
def computeBuildToolsVersion = { ->
project.hasProperty("buildToolsVersion") ? buildToolsVersion : "29.0.2"
}
def enableAnalytics = (project.hasProperty("gatherAnalyticsData") && project.gatherAnalyticsData == "true")
def enableVerboseMDG = project.gradle.startParameter.logLevel.name() == 'DEBUG'
def analyticsFilePath = "$rootDir/analytics/build-statistics.json"
def analyticsCollector = project.ext.AnalyticsCollector.withOutputPath(analyticsFilePath)
if (enableAnalytics) {
analyticsCollector.markUseKotlinPropertyInApp(enableKotlin)
analyticsCollector.writeAnalyticsFile()
}
project.ext.selectedBuildType = project.hasProperty("release") ? "release" : "debug"
buildscript {
// we have moved these initializations here as we need getAppResourcesPath to search for buildscript.gradle files,
// but the buildscript is executed before executing anything else from the gradle file
def initialize = { ->
// the build script will not work with previous versions of the CLI (3.1 or earlier)
def dependenciesJson = file("$rootDir/dependencies.json")
if (!dependenciesJson.exists()) {
throw new BuildCancelledException("""
'dependencies.json' file not found. Check whether the NativeScript CLI has prepared the project beforehand,
and that your NativeScript version is 3.3, or a more recent one. To build an android project with the current
version of the {N} CLI install a previous version of the runtime package - 'tns platform add android@3.2'.
""")
}
project.ext.extractedDependenciesDir = "${project.buildDir}/exploded-dependencies"
project.ext.cleanupAllJarsTimestamp = "${project.buildDir}/cleanupAllJars.timestamp"
project.ext.extractAllJarsTimestamp = "${project.buildDir}/extractAllJars.timestamp"
project.ext.nativescriptDependencies = new JsonSlurper().parseText(dependenciesJson.text)
project.ext.PLATFORMS_ANDROID = "platforms/android"
project.ext.USER_PROJECT_ROOT = "$rootDir/../.."
project.ext.outLogger = services.get(StyledTextOutputFactory).create("colouredOutputLogger")
project.ext.getAppPath = { ->
def relativePathToApp = "app"
def nsConfigFile = file("$USER_PROJECT_ROOT/nsconfig.json")
def nsConfig
if (nsConfigFile.exists()) {
nsConfig = new JsonSlurper().parseText(nsConfigFile.getText("UTF-8"))
}
if (project.hasProperty("appPath")) {
// when appPath is passed through -PappPath=/path/to/app
// the path could be relative or absolute - either case will work
relativePathToApp = appPath
} else if (nsConfig != null && nsConfig.appPath != null) {
relativePathToApp = nsConfig.appPath
}
project.ext.appPath = java.nio.file.Paths.get(USER_PROJECT_ROOT).resolve(relativePathToApp).toAbsolutePath()
return project.ext.appPath
}
project.ext.getAppResourcesPath = { ->
def relativePathToAppResources
def absolutePathToAppResources
def nsConfigFile = file("$USER_PROJECT_ROOT/nsconfig.json")
def nsConfig
if (nsConfigFile.exists()) {
nsConfig = new JsonSlurper().parseText(nsConfigFile.getText("UTF-8"))
}
if (project.hasProperty("appResourcesPath")) {
// when appResourcesPath is passed through -PappResourcesPath=/path/to/App_Resources
// the path could be relative or absolute - either case will work
relativePathToAppResources = appResourcesPath
absolutePathToAppResources = java.nio.file.Paths.get(USER_PROJECT_ROOT).resolve(relativePathToAppResources).toAbsolutePath()
} else if (nsConfig != null && nsConfig.appResourcesPath != null) {
relativePathToAppResources = nsConfig.appResourcesPath
absolutePathToAppResources = java.nio.file.Paths.get(USER_PROJECT_ROOT).resolve(relativePathToAppResources).toAbsolutePath()
} else {
absolutePathToAppResources = "${getAppPath()}/App_Resources"
}
project.ext.appResourcesPath = absolutePathToAppResources
return absolutePathToAppResources
}
}
def applyBuildScriptConfigurations = { ->
def absolutePathToAppResources = getAppResourcesPath()
def pathToBuildScriptGradle = "$absolutePathToAppResources/Android/buildscript.gradle"
def buildScriptGradle = file(pathToBuildScriptGradle)
if (buildScriptGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined buildscript from ${buildScriptGradle}"
apply from: pathToBuildScriptGradle, to: buildscript
}
nativescriptDependencies.each { dep ->
def pathToPluginBuildScriptGradle = "$rootDir/${dep.directory}/$PLATFORMS_ANDROID/buildscript.gradle"
def pluginBuildScriptGradle = file(pathToPluginBuildScriptGradle)
if (pluginBuildScriptGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined buildscript from dependency ${pluginBuildScriptGradle}"
apply from: pathToPluginBuildScriptGradle, to: buildscript
}
}
}
initialize()
applyBuildScriptConfigurations()
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATIONS ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
def applyBeforePluginGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToBeforePluginGradle = "$appResourcesPath/Android/before-plugins.gradle"
def beforePluginGradle = file(pathToBeforePluginGradle)
if (beforePluginGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined configuration from ${beforePluginGradle}"
apply from: pathToBeforePluginGradle
}
}
def applyAppGradleConfiguration = { ->
def appResourcesPath = getAppResourcesPath()
def pathToAppGradle = "$appResourcesPath/Android/app.gradle"
def appGradle = file(pathToAppGradle)
if (appGradle.exists()) {
outLogger.withStyle(Style.SuccessHeader).println "\t + applying user-defined configuration from ${appGradle}"
apply from: pathToAppGradle
} else {
outLogger.withStyle(Style.Info).println "\t + couldn't load user-defined configuration from ${appGradle}. File doesn't exist."
}
}
def applyPluginGradleConfigurations = { ->
nativescriptDependencies.each { dep ->
def includeGradlePath = "$rootDir/${dep.directory}/$PLATFORMS_ANDROID/include.gradle"
if (file(includeGradlePath).exists()) {
apply from: includeGradlePath
}
}
}
def getAppIdentifier = { packageJsonMap ->
def appIdentifier = ""
if (packageJsonMap && packageJsonMap.nativescript) {
appIdentifier = packageJsonMap.nativescript.id
if (!(appIdentifier instanceof String)) {
appIdentifier = appIdentifier.android
}
}
return appIdentifier
}
def setAppIdentifier = { ->
outLogger.withStyle(Style.SuccessHeader).println "\t + setting applicationId"
File packageJsonFile = new File("$USER_PROJECT_ROOT/$PACKAGE_JSON")
if (packageJsonFile.exists()) {
def content = packageJsonFile.getText("UTF-8")
def jsonSlurper = new JsonSlurper()
def packageJsonMap = jsonSlurper.parseText(content)
def appIdentifier = getAppIdentifier(packageJsonMap)
if (appIdentifier) {
project.ext.nsApplicationIdentifier = appIdentifier
android.defaultConfig.applicationId = appIdentifier
}
}
}
android {
if (enableKotlin) {
kotlinOptions {
jvmTarget = '1.8'
}
}
compileSdkVersion computeCompileSdkVersion()
buildToolsVersion computeBuildToolsVersion()
defaultConfig {
def manifest = new XmlSlurper().parse(file(android.sourceSets.main.manifest.srcFile))
def minSdkVer = manifest."uses-sdk"."@android:minSdkVersion".text() ?: 17
minSdkVersion minSdkVer
targetSdkVersion computeTargetSdkVersion()
ndk {
if (onlyX86) {
abiFilters 'x86'
} else {
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
}
dexOptions {
jumboMode = true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets.main {
jniLibs.srcDirs = ["$projectDir/libs/jni", "$projectDir/snapshot-build/build/ndk-build/libs"]
}
signingConfigs {
release {
if (project.hasProperty("release")) {
if (project.hasProperty("ksPath") &&
project.hasProperty("ksPassword") &&
project.hasProperty("alias") &&
project.hasProperty("password")) {
storeFile file(ksPath)
storePassword ksPassword
keyAlias alias
keyPassword password
}
}
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
setAppIdentifier()
applyBeforePluginGradleConfiguration()
applyPluginGradleConfigurations()
applyAppGradleConfiguration()
def initializeMergedAssetsOutputPath = { ->
android.applicationVariants.all { variant ->
if (variant.buildType.name == project.selectedBuildType) {
def task
if (variant.metaClass.respondsTo(variant, "getMergeAssetsProvider")) {
def provider = variant.getMergeAssetsProvider()
task = provider.get();
} else {
// fallback for older android gradle plugin versions
task = variant.getMergeAssets()
}
for (File file : task.getOutputs().getFiles()) {
if (!file.getPath().contains("${File.separator}incremental${File.separator}")) {
project.ext.mergedAssetsOutputPath = file.getPath()
break;
}
}
}
}
}
initializeMergedAssetsOutputPath()
}
def externalRuntimeExists = !findProject(':runtime').is(null)
def pluginDependencies
repositories {
// used for local *.AAR files
pluginDependencies = nativescriptDependencies.collect {
"$rootDir/${it.directory}/$PLATFORMS_ANDROID"
}
// some plugins may have their android dependencies in a /libs subdirectory
pluginDependencies.addAll(nativescriptDependencies.collect {
"$rootDir/${it.directory}/$PLATFORMS_ANDROID/libs"
})
if (!externalRuntimeExists) {
pluginDependencies.add("libs/runtime-libs")
}
def appResourcesPath = getAppResourcesPath()
def localAppResourcesLibraries = "$appResourcesPath/Android/libs"
pluginDependencies.add(localAppResourcesLibraries)
if (pluginDependencies.size() > 0) {
flatDir {
dirs pluginDependencies
}
}
mavenCentral()
}
dependencies {
def androidXLegacyVersion = "1.0.0"
if (project.hasProperty("androidXLegacy")) {
androidXLegacyVersion = androidXLegacy
}
def androidXAppCompatVersion = "1.1.0"
if (project.hasProperty("androidXAppCompat")) {
androidXAppCompatVersion = androidXAppCompat
}
def androidXMaterialVersion = "1.1.0"
if (project.hasProperty("androidXMaterial")) {
androidXMaterialVersion = androidXMaterial
}
def androidXExifInterfaceVersion = "1.2.0"
if (project.hasProperty("androidXExifInterface")) {
androidxExifInterfaceVersion = androidXExifInterface
}
def androidXViewPagerVersion = "1.0.0"
if (project.hasProperty("androidXViewPager")) {
androidXViewPagerVersion = androidXViewPager
}
def androidXFragmentVersion = "1.2.5"
if (project.hasProperty("androidXFragment")) {
androidXFragmentVersion = androidXFragment
}
def androidXTransitionVersion = "1.3.1"
if (project.hasProperty("androidXTransition")) {
androidXTransitionVersion = androidXTransition
}
outLogger.withStyle(Style.SuccessHeader).println "\t + using android X library androidx.legacy:legacy-support-v4:$androidXLegacyVersion"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.legacy:legacy-support-v4:$androidXLegacyVersion"
implementation "androidx.appcompat:appcompat:$androidXAppCompatVersion"
implementation "com.google.android.material:material:$androidXMaterialVersion"
implementation "androidx.exifinterface:exifinterface:$androidXExifInterfaceVersion"
implementation "androidx.viewpager2:viewpager2:$androidXViewPagerVersion"
implementation "androidx.fragment:fragment:$androidXFragmentVersion"
implementation "androidx.transition:transition:$androidXTransitionVersion"
def useV8Symbols = false
def appPackageJsonFile = file("${getAppPath()}/$PACKAGE_JSON")
if (appPackageJsonFile.exists()) {
def appPackageJson = new JsonSlurper().parseText(appPackageJsonFile.text)
useV8Symbols = appPackageJson.android && appPackageJson.android.useV8Symbols
}
if (!useV8Symbols) {
// check whether any of the dependencies require v8 symbols
useV8Symbols = nativescriptDependencies.any {
def packageJsonFile = file("$rootDir/${it.directory}/$PACKAGE_JSON")
def packageJson = new JsonSlurper().parseText(packageJsonFile.text)
return packageJson.nativescript && packageJson.nativescript.useV8Symbols
}
}
if (!externalRuntimeExists) {
def runtime = "nativescript-optimized-with-inspector"
if (project.gradle.startParameter.taskNames.any { it.toLowerCase().contains('release') }) {
runtime = "nativescript-optimized"
}
if (useV8Symbols) {
runtime = "nativescript-regular"
}
outLogger.withStyle(Style.SuccessHeader).println "\t + adding nativescript runtime package dependency: $runtime"
project.dependencies.add("implementation", [name: runtime, ext: "aar"])
} else {
implementation project(':runtime')
}
def kotlinVersion = computeKotlinVersion()
if (enableKotlin) {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
}
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATION PHASE //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
task addDependenciesFromNativeScriptPlugins {
nativescriptDependencies.each { dep ->
def aarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
outLogger.withStyle(Style.SuccessHeader).println "\t + adding aar plugin dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: file("$rootDir/${dep.directory}/$PLATFORMS_ANDROID"), include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
outLogger.withStyle(Style.SuccessHeader).println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
task addDependenciesFromAppResourcesLibraries {
def appResourcesPath = getAppResourcesPath()
def appResourcesLibraries = file("$appResourcesPath/Android/libs")
if (appResourcesLibraries.exists()) {
def aarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.aar"])
aarFiles.each { aarFile ->
def length = aarFile.name.length() - 4
def fileName = aarFile.name[0..<length]
outLogger.withStyle(Style.SuccessHeader).println "\t + adding aar library dependency: " + aarFile.getAbsolutePath()
project.dependencies.add("implementation", [name: fileName, ext: "aar"])
}
def jarFiles = fileTree(dir: appResourcesLibraries, include: ["**/*.jar"])
jarFiles.each { jarFile ->
def jarFileAbsolutePath = jarFile.getAbsolutePath()
outLogger.withStyle(Style.SuccessHeader).println "\t + adding jar plugin dependency: $jarFileAbsolutePath"
pluginsJarLibraries.add(jarFile.getAbsolutePath())
}
project.dependencies.add("implementation", jarFiles)
}
}
if (failOnCompilationWarningsEnabled()) {
tasks.withType(JavaCompile) {
options.compilerArgs << '-Xlint:all' << "-Werror"
options.deprecation = true
}
}
tasks.whenTaskAdded({ org.gradle.api.DefaultTask currentTask ->
if (currentTask =~ /generate.+BuildConfig/) {
currentTask.finalizedBy(extractAllJars)
extractAllJars.finalizedBy(collectAllJars)
}
if (currentTask =~ /compile.+JavaWithJavac/) {
currentTask.dependsOn(runSbg)
currentTask.finalizedBy(buildMetadata)
}
if (currentTask =~ /merge.*Assets/) {
currentTask.shouldRunAfter(buildMetadata)
}
if (currentTask =~ /assemble.*Debug/ || currentTask =~ /assemble.*Release/) {
currentTask.finalizedBy("validateAppIdMatch")
}
})
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// EXECUTUION PHASE /////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
task runSbg(type: BuildToolTask) {
dependsOn "collectAllJars"
if (!findProject(':static-binding-generator').is(null)) {
dependsOn ':static-binding-generator:jar'
}
outputs.dir("$OUTPUT_JAVA_DIR/com/tns/gen")
inputs.dir(INPUT_JS_DIR)
inputs.dir(extractedDependenciesDir)
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
def paramz = new ArrayList<String>()
paramz.add("static-binding-generator.jar")
if (failOnCompilationWarningsEnabled()) {
paramz.add("-show-deprecation-warnings")
}
setOutputs outLogger
args paramz
doFirst {
new File("$OUTPUT_JAVA_DIR/com/tns/gen").deleteDir()
}
}
def failOnCompilationWarningsEnabled() {
return project.hasProperty("failOnCompilationWarnings") && (failOnCompilationWarnings || failOnCompilationWarnings.toBoolean())
}
def explodeAar(File compileDependency, File outputDir) {
logger.info("explodeAar: Extracting ${compileDependency.path} -> ${outputDir.path}")
if (compileDependency.name.endsWith(".aar")) {
java.util.jar.JarFile jar = new java.util.jar.JarFile(compileDependency)
Enumeration enumEntries = jar.entries()
while (enumEntries.hasMoreElements()) {
java.util.jar.JarEntry file = (java.util.jar.JarEntry) enumEntries.nextElement()
if (file.name.endsWith(".jar")) {
def targetFile = new File(outputDir, file.name)
InputStream inputStream = jar.getInputStream(file)
new File(targetFile.parent).mkdirs()
Files.copy(inputStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING)
}
if (file.isDirectory()) {
continue
}
}
jar.close()
} else if (compileDependency.name.endsWith(".jar")) {
copy {
from compileDependency.absolutePath
into outputDir
}
}
}
def md5(String string) {
MessageDigest digest = MessageDigest.getInstance("MD5")
digest.update(string.bytes)
return new BigInteger(1, digest.digest()).toString(16).padLeft(32, '0')
}
class WorkerTask extends DefaultTask {
@Inject
WorkerExecutor getWorkerExecutor() {
throw new UnsupportedOperationException()
}
}
class EmptyRunnable implements Runnable {
void run() {
}
}
def getMergedAssetsOutputPath() {
if (!project.hasProperty("mergedAssetsOutputPath")) {
// mergedAssetsOutputPath not found fallback to the default value for android gradle plugin 3.5.1
project.ext.mergedAssetsOutputPath = "$projectDir/build/intermediates/merged_assets/" + project.selectedBuildType + "/out"
}
return project.ext.mergedAssetsOutputPath
}
// Discover all jars and dynamically create tasks for the extraction of each of them
project.ext.allJars = []
afterEvaluate { project ->
def buildType = project.selectedBuildType == "release" ? "Release" : "Debug"
def jars = []
def artifactType = Attribute.of('artifactType', String)
configurations.all { config ->
if (config.name.toLowerCase().endsWith("${buildType}RuntimeClasspath".toLowerCase())) {
config.incoming.artifactView {
attributes {
it.attribute(artifactType, 'jar')
}
}.artifacts.each {
processJar(it.file, jars)
}
def projectDependencies = config.getAllDependencies().withType(ProjectDependency)
def dependentProjects = projectDependencies*.dependencyProject
dependentProjects.findAll {
// if there's a project dependency search for its result jar file in the build/intermediates/runtime_library_classes folder
// this is the output folder in gradle 5.1.1, but it can be changed in the future versions of gradle
def jarDir = new File("${it.getBuildDir()}/intermediates/runtime_library_classes/${buildType.toLowerCase()}")
if (jarDir.exists()) {
jarDir.eachFileRecurse(FileType.FILES) { file ->
if (file.path.endsWith(".jar")) {
processJar(file, jars)
}
}
} else {
outLogger.withStyle(Style.Info).println "WARNING: Folder ${jarDir.path} does not exists, the dependent project's classes won't be included in the metadata"
}
}
}
}
}
def processJar(File jar, jars) {
if (!jars.contains(jar)) {
jars.add(jar)
def destDir = md5(jar.path)
def outputDir = new File(Paths.get(extractedDependenciesDir, destDir).normalize().toString())
def taskName = "extract_${jar.name}_to_${destDir}"
logger.debug("Creating dynamic task ${taskName}")
// Add discovered jars as dependencies of cleanupAllJars.
// This is cruicial for cloud builds because they are different
// on each incremental build (as each time the gradle user home
// directory is a randomly generated string)
cleanupAllJars.inputs.files jar
task "${taskName}"(type: WorkerTask) {
dependsOn cleanupAllJars
extractAllJars.dependsOn it
// This dependency seems redundant but probably due to some Gradle issue with workers,
// without it `runSbg` sporadically starts before all extraction tasks have finished and
// fails due to missing JARs
runSbg.dependsOn it
inputs.files jar
outputs.dir outputDir
doLast {
// Runing in parallel no longer seems to bring any benefit.
// It mattered only when we were extracting JARs from AARs.
// To try it simply remove the following comments.
// workerExecutor.submit(EmptyRunnable.class) {
explodeAar(jar, outputDir)
// }
}
}
project.ext.allJars.add([file: jar, outputDir: outputDir])
}
}
task cleanupAllJars {
// We depend on the list of libs directories that might contain aar or jar files
// and on the list of all discovered jars
inputs.files(pluginDependencies)
outputs.files cleanupAllJarsTimestamp
doLast {
def allDests = project.ext.allJars*.outputDir*.name
def dir = new File(extractedDependenciesDir)
if (dir.exists()) {
dir.eachDir {
// An old directory which is no longer a dependency (e.g. orphaned by a deleted plugin)
if (!allDests.contains(it.name)) {
logger.info("Task cleanupAllJars: Deleting orphaned ${it.path}")
org.apache.commons.io.FileUtils.deleteDirectory(it)
}
}
}
new File(cleanupAllJarsTimestamp).write ""
}
}
// Placeholder task which depends on all dynamically generated extraction tasks
task extractAllJars {
dependsOn cleanupAllJars
outputs.files extractAllJarsTimestamp
doLast {
new File(cleanupAllJarsTimestamp).write ""
}
}
task collectAllJars {
dependsOn extractAllJars
description "gathers all paths to jar dependencies before building metadata with them"
def sdkPath = android.sdkDirectory.getAbsolutePath()
def androidJar = sdkPath + "/platforms/" + android.compileSdkVersion + "/android.jar"
doFirst {
def allJarPaths = new LinkedList<String>()
allJarPaths.add(androidJar)
allJarPaths.addAll(pluginsJarLibraries)
def ft = fileTree(dir: extractedDependenciesDir, include: "**/*.jar")
ft.each { currentJarFile ->
allJarPaths.add(currentJarFile.getAbsolutePath())
}
new File("$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each { out.println it }
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriter { out ->
allJarPaths.each {
if (it.endsWith(".jar")) {
out.println it
}
}
}
new File("$BUILD_TOOLS_PATH/$SBG_INPUT_FILE").withWriter { out ->
out.println INPUT_JS_DIR
}
new File("$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE").withWriter { out ->
out.println OUTPUT_JAVA_DIR
}
allJarLibraries.addAll(allJarPaths)
}
}
task copyMetadataFilters(type: Copy) {
from "$rootDir/whitelist.mdg", "$rootDir/blacklist.mdg"
into "$BUILD_TOOLS_PATH"
}
task copyMetadata {
doLast {
copy {
from "$projectDir/src/main/assets/metadata"
into getMergedAssetsOutputPath() + "/metadata"
}
}
}
task buildMetadata(type: BuildToolTask) {
if (!findProject(':android-metadata-generator').is(null)) {
dependsOn ':android-metadata-generator:jar'
}
dependsOn copyMetadataFilters
// As some external gradle plugins can reorder the execution order of the tasks it may happen that buildMetadata is executed after merge{Debug/Release}Assets
// in that case the metadata won't be included in the result apk and it will crash, so to avoid this we are adding the copyMetadata task which will manually copy
// the metadata files in the merge assets folder and they will be added to the result apk
// The next line is added to avoid adding another copyData implementation from the firebase plugin - https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/3943bb9147f43c41599e801d026378eba93d3f3a/publish/scripts/installer.js#L1105
//buildMetadata.finalizedBy(copyMetadata)
finalizedBy copyMetadata
description "builds metadata with provided jar dependencies"
inputs.files("$MDG_JAVA_DEPENDENCIES")
// make MDG aware of whitelist.mdg and blacklist.mdg files
inputs.files(project.fileTree(dir: "$rootDir", include: "**/*.mdg"))
def classesDir = "$buildDir/intermediates/javac"
inputs.dir(classesDir)
def kotlinClassesDir = "$buildDir/tmp/kotlin-classes"
if (file(kotlinClassesDir).exists()) {
inputs.dir(kotlinClassesDir)
}
outputs.files("$METADATA_OUT_PATH/treeNodeStream.dat", "$METADATA_OUT_PATH/treeStringsStream.dat", "$METADATA_OUT_PATH/treeValueStream.dat")
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
doFirst {
// get compiled classes to pass to metadata generator
// these need to be called after the classes have compiled
assert file(classesDir).exists()
new File(getMergedAssetsOutputPath() + "/metadata").deleteDir()
def classesSubDirs = new File(classesDir).listFiles()
def selectedBuildType = project.ext.selectedBuildType
def generatedClasses = new LinkedList<String>()
for (File subDir : classesSubDirs) {
if (subDir.getName().equals(selectedBuildType)) {
generatedClasses.add(subDir.getAbsolutePath())
}
}
if (file(kotlinClassesDir).exists()) {
def kotlinClassesSubDirs = new File(kotlinClassesDir).listFiles()
for (File subDir : kotlinClassesSubDirs) {
if (subDir.getName() == selectedBuildType) {
generatedClasses.add(subDir.getAbsolutePath())
}
}
}
new File("$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR").withWriter { out ->
out.println "$METADATA_OUT_PATH"
}
new File("$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES").withWriterAppend { out ->
generatedClasses.each { out.println it }
}
setOutputs outLogger
def paramz = new ArrayList<String>()
paramz.add("android-metadata-generator.jar")
if(enableAnalytics){
paramz.add("analyticsFilePath=$analyticsFilePath")
}
if(enableVerboseMDG){
paramz.add("verbose")
}
args paramz.toArray()
}
}
task generateTypescriptDefinitions(type: BuildToolTask) {
if (!findProject(':dts-generator').is(null)) {
dependsOn ':dts-generator:jar'
}
def paramz = new ArrayList<String>()
def includeDirs = ["com.android.support", "/platforms/" + android.compileSdkVersion]
workingDir "$BUILD_TOOLS_PATH"
main "-jar"
doFirst {
delete "$TYPINGS_PATH"
paramz.add("dts-generator.jar")
paramz.add("-input")
for (String jarPath : allJarLibraries) {
// don't generate typings for runtime jars and classes
if (shouldIncludeDirForTypings(jarPath, includeDirs)) {
paramz.add(jarPath)
}
}
paramz.add("-output")
paramz.add("$TYPINGS_PATH")
new File("$TYPINGS_PATH").mkdirs()
logger.info("Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', ''))
outLogger.withStyle(Style.SuccessHeader).println "Task generateTypescriptDefinitions: Call dts-generator.jar with arguments: " + paramz.toString().replaceAll(',', '')
setOutputs outLogger
args paramz.toArray()
}
}
generateTypescriptDefinitions.onlyIf {
(project.hasProperty("generateTypings") && Boolean.parseBoolean(project.generateTypings)) || PASSED_TYPINGS_PATH != null
}
collectAllJars.finalizedBy(generateTypescriptDefinitions)
static def shouldIncludeDirForTypings(path, includeDirs) {
for (String p : includeDirs) {
if (path.indexOf(p) > -1) {
return true
}
}
return false
}
task copyTypings {
doLast {
outLogger.withStyle(Style.Info).println "Copied generated typings to application root level. Make sure to import android.d.ts in reference.d.ts"
copy {
from "$TYPINGS_PATH"
into "$USER_PROJECT_ROOT"
}
}
}
copyTypings.onlyIf { generateTypescriptDefinitions.didWork }
generateTypescriptDefinitions.finalizedBy(copyTypings)
task validateAppIdMatch {
doLast {
def lineSeparator = System.getProperty("line.separator")
if (project.hasProperty("nsApplicationIdentifier") && !project.hasProperty("release")) {
if (project.nsApplicationIdentifier != android.defaultConfig.applicationId) {
def errorMessage = "${lineSeparator}WARNING: The Application identifier is different from the one inside \"package.json\" file.$lineSeparator" +
"NativeScript CLI might not work properly.$lineSeparator" +
"Remove applicationId from app.gradle and update the \"nativescript.id\" in package.json.$lineSeparator" +
"Actual: ${android.defaultConfig.applicationId}$lineSeparator" +
"Expected(from \"package.json\"): ${project.nsApplicationIdentifier}$lineSeparator"
logger.error(errorMessage)
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// OPTIONAL TASKS //////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
//////// custom clean ///////////
task cleanSbg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$SBG_JS_PARSED_FILES",
"$BUILD_TOOLS_PATH/$SBG_JAVA_DEPENDENCIES",
"$BUILD_TOOLS_PATH/$SBG_INTERFACE_NAMES",
"$BUILD_TOOLS_PATH/$SBG_BINDINGS_NAME",
"$BUILD_TOOLS_PATH/$SBG_INPUT_FILE",
"$BUILD_TOOLS_PATH/$SBG_OUTPUT_FILE",
"$OUTPUT_JAVA_DIR/com/tns/gen"
}
task cleanMdg(type: Delete) {
delete "$BUILD_TOOLS_PATH/$MDG_OUTPUT_DIR",
"$BUILD_TOOLS_PATH/whitelist.mdg",
"$BUILD_TOOLS_PATH/blacklist.mdg",
"$BUILD_TOOLS_PATH/$MDG_JAVA_DEPENDENCIES",
"$METADATA_OUT_PATH"
}
cleanSbg.dependsOn(cleanMdg)
clean.dependsOn(cleanSbg)

View file

@ -1,4 +0,0 @@
{
"prepareTime": "Wed Dec 30 2020 14:50:17 GMT+0530 (India Standard Time)",
"buildTime": "Wed Dec 30 2020 14:50:40 GMT+0530 (India Standard Time)"
}

View file

@ -1,57 +0,0 @@
{
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/tns-java-classes.js": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/fonts/Orkney-Medium.otf": "c11f050eaecbb1cc95c90bcc25f47bc0dcd35ec4",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/fonts/Orkney-Regular.otf": "eca386e11c6c51a2800a24a456bebcbc2a699b98",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/package.json": "66e3387f8d71589213a52a9179935c1f0c93181b",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/camera.png": "73911d2bab8115193301e1638d74e6a9efdb7305",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/detail.png": "dde1aae9a0523df821a8ce26841ed37d2ef7b89c",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/ic_launcher.png": "1f6cb451f5e8f74fca7dd14a6e2078bb40c3def4",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/ic_launcher_foreground.png": "aeb5840f7f88a0a044eff038ad7f65a1f12b93fc",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/logo.png": "2db8a76318f10c944f5492ad65711b775d572e84",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/photo.png": "0bbf60c565e64e27e66afa8ac3fe27e33332ebd3",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/plus.png": "85f2e2ab1e61d49be720fee26b418309aff124bd",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-hdpi/share.png": "016114dff194ffb303294fbcaf8f6456401236fe",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/camera.png": "1fc838c8e4afcfbbc3bfd10b7211b9da8e8995af",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/detail.png": "9ab81bd03e2e7b2f9c8cfc5041f8b62d0bb67fe3",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/ic_launcher.png": "ae5dd9afe7e5cdabacb5490d9ece9df40c11b929",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/logo.png": "59db1214bf003baf49b6cdd0d7ab3969d0dfdbab",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/photo.png": "3ca5bda741d56796587353034abdf3c03e2679e7",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/plus.png": "9a4bb87916b4aa350358f46b23d88bd6503af349",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-ldpi/share.png": "bf57c3eff355c51f220f6b65ae1e534774dc92ae",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/camera.png": "47a299e4cbaaa0b30897ecfdb7cec2b82ac72df5",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/detail.png": "4d914f8b5312bc96eb81eb9dc052eef07bfd52cb",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/ic_launcher.png": "c52483af0ce6eec905fbef292013d901fc2b9110",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/ic_launcher_foreground.png": "9fd235ecf6548d5ab9e1fe3224172ce8a1558c8a",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/logo.png": "944eb84979a774da3082bbaa323371f63e6945f4",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/photo.png": "9399bee456e2cc3f4f4f071d3ef46073f9d05e59",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/plus.png": "2d75915cae762fe13238921209d7a1fbc896ef31",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-mdpi/share.png": "5f4976a18eeacc8509e7bd71d9cc2dae051af149",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/camera.png": "56e67577db1d4ddd5cf78371d523559a9054c477",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/detail.png": "ec0da35c95f4773c8c26e70647b6a974103e9944",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/ic_launcher.png": "681a23ee3bcbb5c744cb80f224a4baedad3f0075",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/ic_launcher_foreground.png": "58375b6039b0bf0fc65802a162d84cba8f6fb368",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/logo.png": "d55b18eecf5018f9a3adc6ebcc24d309dbed4493",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/photo.png": "7a9b1b430fe189e3a918743044bcb77a932b6ccf",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/plus.png": "7d34efbfa76ce57eb39717c8d647b653a0e94790",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xhdpi/share.png": "aa8db89c92d31454c73ef9703f6e4e86e713cf14",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/camera.png": "b1957b0ed4e5e87a5f6ace6206f7275f9018a43e",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/detail.png": "b6ba2ab8f9ca73192121cfa43c04fd9949eea1d1",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/ic_launcher.png": "2e42d3e335309a0b6c625927bdc2c3a44e51db15",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png": "9e04a41c390fe7cce4bd27aacbfcffa7e569e0aa",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/logo.png": "6ef92b82e503374659d0235651cf1336dbb7ecd4",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/photo.png": "7b18cd100f4257093462b37a66dd668af79ffa6e",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/plus.png": "76176fc03af105bd08cdce12f6215b873242c1b5",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxhdpi/share.png": "c93bd7ad2384dc64e9bb1f91c0c75339fa57c046",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/camera.png": "ded407b62061adf527a977dc02d81ce9b8f8d99c",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/detail.png": "5f8269086112fef82cd870d7280390e554d21c8d",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/ic_launcher.png": "21525ef0646e7613f63b1b0ffe5cf7a8e7eac25b",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png": "81b06e543dd83ca98b6848dabf1bf6ad81be64f5",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/logo.png": "680357c1903bd7f4d7e7dd7f76a3a742a4c966ab",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/photo.png": "6500603c21d7cc1738db44ba26157ab47b621747",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/plus.png": "02eab956eabbe68bb27973582c569b822f130d2a",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/resources/Android/src/main/res/drawable-xxxhdpi/share.png": "ebe8381c0e77d40abd5f41daf94532248caaa9dc",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/runtime.js": "e46a5b846bc23d10ebce68cde16be7cd70e102f4",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/fonts/boxicons.ttf": "6c9944326ed3c901afcb78a9ed07906f04f9cbb2",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/bundle.js": "3fbfd0ad9e7ca4368f83a8f1900ecb003c11948a",
"/mnt/82e5ff15-70b8-44a5-bb66-55688fc2381f/Freelance/Projects/WIP/EnRecipes/Developement/EnRecipes-App/platforms/android/app/src/main/assets/app/vendor.js": "cfe29102f0c4d6f7ff8d95a4194ca064f5444a3a"
}

View file

@ -1,48 +0,0 @@
import groovy.json.JsonBuilder
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.Path
class AnalyticsCollector{
private final String analyticsFilePath
private boolean hasUseKotlinPropertyInApp = false
private boolean hasKotlinRuntimeClasses = false
private AnalyticsCollector(String analyticsFilePath){
this.analyticsFilePath = analyticsFilePath
}
static AnalyticsCollector withOutputPath(String analyticsFilePath){
return new AnalyticsCollector(analyticsFilePath)
}
void markUseKotlinPropertyInApp(boolean useKotlin) {
hasUseKotlinPropertyInApp = useKotlin
}
void writeAnalyticsFile() {
def jsonBuilder = new JsonBuilder()
def kotlinUsageData = new Object()
kotlinUsageData.metaClass.hasUseKotlinPropertyInApp = hasUseKotlinPropertyInApp
kotlinUsageData.metaClass.hasKotlinRuntimeClasses = hasKotlinRuntimeClasses
jsonBuilder(kotlinUsage: kotlinUsageData)
def prettyJson = jsonBuilder.toPrettyString()
Path statisticsFilePath = Paths.get(analyticsFilePath)
if (Files.notExists(statisticsFilePath)) {
Files.createDirectories(statisticsFilePath.getParent())
Files.createFile(statisticsFilePath)
}
Files.write(statisticsFilePath, prettyJson.getBytes(StandardCharsets.UTF_8))
}
}
ext.AnalyticsCollector = AnalyticsCollector

View file

@ -1,50 +0,0 @@
import static org.gradle.internal.logging.text.StyledTextOutput.Style
class BuildToolTask extends JavaExec {
void setOutputs(def logger) {
def logFile = new File("$workingDir/${name}.log")
if(logFile.exists()) {
logFile.delete()
}
standardOutput new FileOutputStream(logFile)
errorOutput new FailureOutputStream(logger, logFile)
}
}
class FailureOutputStream extends OutputStream {
private logger
private File logFile
private currentLine = ""
private firstWrite = true
FailureOutputStream(inLogger, inLogFile) {
logger = inLogger
logFile = inLogFile
}
@Override
void write(int i) throws IOException {
if(firstWrite) {
println ""
firstWrite = false
}
currentLine += String.valueOf((char) i)
}
@Override
void flush() {
if(currentLine?.trim()) {
logger.withStyle(Style.Failure).println currentLine.trim()
currentLine = ""
}
}
@Override
void close() {
if(!firstWrite && logFile.exists()) {
logger.withStyle(Style.Info).println "Detailed log here: ${logFile.getAbsolutePath()}\n"
}
super.close()
}
}
ext.BuildToolTask = BuildToolTask

View file

@ -1,52 +0,0 @@
import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.internal.logging.text.StyledTextOutput.Style
def outLogger = services.get(StyledTextOutputFactory).create("colouredOutputLogger")
class CustomExecutionLogger extends BuildAdapter implements TaskExecutionListener {
private logger
private failedTask
CustomExecutionLogger(passedLogger) {
logger = passedLogger
}
void buildStarted(Gradle gradle) {
failedTask = null
}
void beforeExecute(Task task) {
}
void afterExecute(Task task, TaskState state) {
def failure = state.getFailure()
if(failure) {
failedTask = task
}
}
void buildFinished(BuildResult result) {
def failure = result.getFailure()
if(failure) {
if(failedTask && (failedTask.getClass().getName().contains("BuildToolTask"))) {
// the error from this task is already logged
return
}
println ""
logger.withStyle(Style.FailureHeader).println failure.getMessage()
def causeException = failure.getCause()
while (causeException != null) {
failure = causeException
causeException = failure.getCause()
}
if(failure != causeException) {
logger.withStyle(Style.Failure).println failure.getMessage()
}
println ""
}
}
}
gradle.useLogger(new CustomExecutionLogger(outLogger))

View file

@ -1,426 +0,0 @@
package com.tns;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.Manifest;
import android.app.Activity;
import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import com.google.android.material.tabs.TabLayout;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
class ErrorReport implements TabLayout.OnTabSelectedListener {
public static final String ERROR_FILE_NAME = "hasError";
private static AppCompatActivity activity;
private TabLayout tabLayout;
private ViewPager viewPager;
private Context context;
private static String exceptionMsg;
private static String logcatMsg;
private static boolean checkingForPermissions = false;
private final static String EXTRA_NATIVESCRIPT_ERROR_REPORT = "NativeScriptErrorMessage";
private final static String EXTRA_ERROR_REPORT_MSG = "msg";
private final static String EXTRA_PID = "pID";
private final static int EXTRA_ERROR_REPORT_VALUE = 1;
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
// Will prevent error activity from killing process if permission request dialog pops up
public static boolean isCheckingForPermissions() {
return checkingForPermissions;
}
public static void resetCheckingForPermissions() {
checkingForPermissions = false;
}
// The following will not compile if uncommented with compileSdk lower than 23
public static void verifyStoragePermissions(Activity activity) {
// Check if we have write permission
final int version = Build.VERSION.SDK_INT;
if (version >= 23) {
try {
// Necessary to work around compile errors with compileSdk 22 and lower
Method checkSelfPermissionMethod;
try {
checkSelfPermissionMethod = ActivityCompat.class.getMethod("checkSelfPermission", Context.class, String.class);
} catch (NoSuchMethodException e) {
// method wasn't found, so there is no need to handle permissions explicitly
if (Util.isDebuggableApp(activity)) {
e.printStackTrace();
}
return;
}
int permission = (int) checkSelfPermissionMethod.invoke(null, activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permission != PackageManager.PERMISSION_GRANTED) {
// We don't have permission so prompt the user
Method requestPermissionsMethod = ActivityCompat.class.getMethod("requestPermissions", Activity.class, PERMISSIONS_STORAGE.getClass(), int.class);
checkingForPermissions = true;
requestPermissionsMethod.invoke(null, activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
Toast.makeText(activity, "Couldn't resolve permissions", Toast.LENGTH_LONG).show();
if (Util.isDebuggableApp(activity)) {
e.printStackTrace();
}
return;
}
}
}
public ErrorReport(AppCompatActivity activity) {
ErrorReport.activity = activity;
this.context = activity.getApplicationContext();
}
static boolean startActivity(final Context context, String errorMessage) {
final Intent intent = getIntent(context);
if (intent == null) {
return false; // (if in release mode) don't do anything
}
intent.putExtra(EXTRA_ERROR_REPORT_MSG, errorMessage);
String PID = Integer.toString(android.os.Process.myPid());
intent.putExtra(EXTRA_PID, PID);
createErrorFile(context);
try {
startPendingErrorActivity(context, intent);
} catch (CanceledException e) {
Log.d("ErrorReport", "Couldn't send pending intent! Exception: " + e.getMessage());
}
killProcess(context);
return true;
}
static void killProcess(Context context) {
// finish current activity and all below it first
if (context instanceof Activity) {
((Activity) context).finishAffinity();
}
// kill process
android.os.Process.killProcess(android.os.Process.myPid());
}
static void startPendingErrorActivity(Context context, Intent intent) throws CanceledException {
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
pendingIntent.send(context, 0, intent);
}
static String getErrorMessage(Throwable ex) {
String content;
PrintStream ps = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ps = new PrintStream(baos);
ex.printStackTrace(ps);
try {
content = baos.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
content = e.getMessage();
}
} finally {
if (ps != null) {
ps.close();
}
}
return content;
}
/*
* Gets the process Id of the running app and filters all
* output that doesn't belong to that process
* */
public static String getLogcat(String pId) {
String content;
try {
String logcatCommand = "logcat -d";
Process process = java.lang.Runtime.getRuntime().exec(logcatCommand);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder();
String line = "";
String lineSeparator = System.getProperty("line.separator");
while ((line = bufferedReader.readLine()) != null) {
if (line.contains(pId)) {
log.append(line);
log.append(lineSeparator);
}
}
content = log.toString();
} catch (IOException e) {
content = "Failed to read logcat";
Log.e("TNS.Android", content);
}
return content;
}
static Intent getIntent(Context context) {
Class<?> errorActivityClass;
if (Util.isDebuggableApp(context)) {
errorActivityClass = ErrorReportActivity.class;
} else {
return null;
}
Intent intent = new Intent(context, errorActivityClass);
intent.putExtra(EXTRA_NATIVESCRIPT_ERROR_REPORT, EXTRA_ERROR_REPORT_VALUE);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
return intent;
}
static boolean hasIntent(Intent intent) {
int value = intent.getIntExtra(EXTRA_NATIVESCRIPT_ERROR_REPORT, 0);
return value == EXTRA_ERROR_REPORT_VALUE;
}
void buildUI() {
Intent intent = activity.getIntent();
exceptionMsg = intent.getStringExtra(EXTRA_ERROR_REPORT_MSG);
String processId = intent.getStringExtra(EXTRA_PID);
logcatMsg = getLogcat(processId);
int errActivityId = this.context.getResources().getIdentifier("error_activity", "layout", this.context.getPackageName());
activity.setContentView(errActivityId);
int toolBarId = this.context.getResources().getIdentifier("toolbar", "id", this.context.getPackageName());
Toolbar toolbar = (Toolbar) activity.findViewById(toolBarId);
activity.setSupportActionBar(toolbar);
final int tabLayoutId = this.context.getResources().getIdentifier("tabLayout", "id", this.context.getPackageName());
tabLayout = (TabLayout) activity.findViewById(tabLayoutId);
tabLayout.addTab(tabLayout.newTab().setText("Exception"));
tabLayout.addTab(tabLayout.newTab().setText("Logcat"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
int pagerId = this.context.getResources().getIdentifier("pager", "id", this.context.getPackageName());
viewPager = (ViewPager) activity.findViewById(pagerId);
Pager adapter = new Pager(activity.getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
tabLayout.getTabAt(position).select();
viewPager.setCurrentItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
this.addOnTabSelectedListener(tabLayout);
}
private void addOnTabSelectedListener(TabLayout tabLayout) {
tabLayout.addOnTabSelectedListener(this);
}
private static void createErrorFile(final Context context) {
try {
File errFile = new File(context.getFilesDir(), ERROR_FILE_NAME);
errFile.createNewFile();
} catch (IOException e) {
Log.d("ErrorReport", e.getMessage());
}
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
private class Pager extends FragmentStatePagerAdapter {
int tabCount;
@SuppressWarnings("deprecation")
public Pager(FragmentManager fm, int tabCount) {
super(fm);
this.tabCount = tabCount;
}
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ExceptionTab();
case 1:
return new LogcatTab();
default:
return null;
}
}
@Override
public int getCount() {
return tabCount;
}
}
public static class ExceptionTab extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int exceptionTabId = container.getContext().getResources().getIdentifier("exception_tab", "layout", container.getContext().getPackageName());
View view = inflater.inflate(exceptionTabId, container, false);
int txtViewId = container.getContext().getResources().getIdentifier("txtErrorMsg", "id", container.getContext().getPackageName());
TextView txtErrorMsg = (TextView) view.findViewById(txtViewId);
txtErrorMsg.setText(exceptionMsg);
txtErrorMsg.setMovementMethod(new ScrollingMovementMethod());
int btnCopyExceptionId = container.getContext().getResources().getIdentifier("btnCopyException", "id", container.getContext().getPackageName());
Button copyToClipboard = (Button) view.findViewById(btnCopyExceptionId);
copyToClipboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("nsError", exceptionMsg);
clipboard.setPrimaryClip(clip);
}
});
return view;
}
}
public static class LogcatTab extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int logcatTabId = container.getContext().getResources().getIdentifier("logcat_tab", "layout", container.getContext().getPackageName());
View view = inflater.inflate(logcatTabId, container, false);
int textViewId = container.getContext().getResources().getIdentifier("logcatMsg", "id", container.getContext().getPackageName());
TextView txtlogcatMsg = (TextView) view.findViewById(textViewId);
txtlogcatMsg.setText(logcatMsg);
txtlogcatMsg.setMovementMethod(new ScrollingMovementMethod());
final String logName = "Log-" + new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
int btnCopyLogcatId = container.getContext().getResources().getIdentifier("btnCopyLogcat", "id", container.getContext().getPackageName());
Button copyToClipboard = (Button) view.findViewById(btnCopyLogcatId);
copyToClipboard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
verifyStoragePermissions(activity);
if (!isCheckingForPermissions()) {
try {
File dir = new File(Environment.getExternalStorageDirectory().getPath() + "/logcat-reports/");
dir.mkdirs();
File logcatReportFile = new File(dir, logName);
FileOutputStream stream = new FileOutputStream(logcatReportFile);
OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8");
writer.write(logcatMsg);
writer.close();
String logPath = dir.getPath() + "/" + logName;
ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("logPath", logPath);
clipboard.setPrimaryClip(clip);
Toast.makeText(activity, "Path copied to clipboard: " + logPath, Toast.LENGTH_LONG).show();
} catch (Exception e) {
String err = "Could not write logcat report to sdcard. Make sure you have allowed access to external storage!";
Toast.makeText(activity, err, Toast.LENGTH_LONG).show();
if (Util.isDebuggableApp(container.getContext())) {
e.printStackTrace();
}
}
}
}
});
return view;
}
}
}

View file

@ -1,51 +0,0 @@
package com.tns;
import android.app.Application;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Toast;
import java.lang.reflect.Method;
import static com.tns.ErrorReport.isCheckingForPermissions;
import static com.tns.ErrorReport.resetCheckingForPermissions;
public class ErrorReportActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
setTheme(androidx.appcompat.R.style.Theme_AppCompat_NoActionBar);
super.onCreate(savedInstanceState);
Application app = this.getApplication();
Logger logger = new LogcatLogger(app);
RuntimeHelper.initLiveSync(null, logger, app);
new ErrorReport(this).buildUI();
}
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
if (!isCheckingForPermissions()) {
ErrorReport.killProcess(this);
}
}
// @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
try {
Method onRequestPermissionsResultMethod = AppCompatActivity.class.getMethod("onRequestPermissionsResult", int.class, permissions.getClass(), grantResults.getClass());
onRequestPermissionsResultMethod.invoke(new AppCompatActivity() /* never do this */, requestCode, permissions, grantResults);
resetCheckingForPermissions();
} catch (Exception e) {
if (Util.isDebuggableApp(this)) {
e.printStackTrace();
}
Toast.makeText(this, "Couldn't resolve permissions", Toast.LENGTH_LONG).show();
resetCheckingForPermissions();
}
}
}

View file

@ -1,346 +0,0 @@
package com.tns;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.util.Log;
public class NativeScriptSyncService {
private static String SYNC_ROOT_SOURCE_DIR = "/data/local/tmp/";
private static final String SYNC_SOURCE_DIR = "/sync/";
private static final String FULL_SYNC_SOURCE_DIR = "/fullsync/";
private static final String REMOVED_SYNC_SOURCE_DIR = "/removedsync/";
private final Runtime runtime;
private static Logger logger;
private final Context context;
private final String syncPath;
private final String fullSyncPath;
private final String removedSyncPath;
private final File fullSyncDir;
private final File syncDir;
private final File removedSyncDir;
private LocalServerSocketThread localServerThread;
private Thread localServerJavaThread;
public NativeScriptSyncService(Runtime runtime, Logger logger, Context context) {
this.runtime = runtime;
NativeScriptSyncService.logger = logger;
this.context = context;
syncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + SYNC_SOURCE_DIR;
fullSyncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + FULL_SYNC_SOURCE_DIR;
removedSyncPath = SYNC_ROOT_SOURCE_DIR + context.getPackageName() + REMOVED_SYNC_SOURCE_DIR;
fullSyncDir = new File(fullSyncPath);
syncDir = new File(syncPath);
removedSyncDir = new File(removedSyncPath);
}
public void sync() {
if (logger != null && logger.isEnabled()) {
logger.write("Sync is enabled:");
logger.write("Sync path : " + syncPath);
logger.write("Full sync path : " + fullSyncPath);
logger.write("Removed files sync path: " + removedSyncPath);
}
if (fullSyncDir.exists()) {
executeFullSync(context, fullSyncDir);
return;
}
if (syncDir.exists()) {
executePartialSync(context, syncDir);
}
if (removedSyncDir.exists()) {
executeRemovedSync(context, removedSyncDir);
}
}
private class LocalServerSocketThread implements Runnable {
private volatile boolean running;
private final String name;
private ListenerWorker commThread;
private LocalServerSocket serverSocket;
public LocalServerSocketThread(String name) {
this.name = name;
this.running = false;
}
public void stop() {
this.running = false;
try {
serverSocket.close();
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
public void run() {
running = true;
try {
serverSocket = new LocalServerSocket(this.name);
while (running) {
LocalSocket socket = serverSocket.accept();
commThread = new ListenerWorker(socket);
new Thread(commThread).start();
}
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
}
private class ListenerWorker implements Runnable {
private final DataInputStream input;
private Closeable socket;
private OutputStream output;
public ListenerWorker(LocalSocket socket) throws IOException {
this.socket = socket;
input = new DataInputStream(socket.getInputStream());
output = socket.getOutputStream();
}
public void run() {
try {
int length = input.readInt();
input.readFully(new byte[length]); // ignore the payload
executePartialSync(context, syncDir);
executeRemovedSync(context, removedSyncDir);
runtime.runScript(new File(NativeScriptSyncService.this.context.getFilesDir(), "internal/livesync.js"));
try {
output.write(1);
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
socket.close();
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
}
public void startServer() {
localServerThread = new LocalServerSocketThread(context.getPackageName() + "-livesync");
localServerJavaThread = new Thread(localServerThread);
localServerJavaThread.start();
}
public static boolean isSyncEnabled(Context context) {
int flags;
boolean shouldExecuteSync = false;
try {
flags = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).applicationInfo.flags;
shouldExecuteSync = ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0);
} catch (NameNotFoundException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
return false;
}
return shouldExecuteSync;
}
final FileFilter deletingFilesFilter = new FileFilter() {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return true;
}
boolean success = pathname.delete();
if (!success) {
logger.write("Syncing: file not deleted: " + pathname.getAbsolutePath().toString());
}
return false;
}
};
private void deleteDir(File directory) {
File[] subDirectories = directory.listFiles(deletingFilesFilter);
if (subDirectories != null) {
for (int i = 0; i < subDirectories.length; i++) {
File subDir = subDirectories[i];
deleteDir(subDir);
}
}
boolean success = directory.delete();
if (!success && directory.exists()) {
logger.write("Syncing: directory not deleted: " + directory.getAbsolutePath().toString());
}
}
private void moveFiles(File sourceDir, String sourceRootAbsolutePath, String targetRootAbsolutePath) {
File[] files = sourceDir.listFiles();
if (files != null) {
if (logger.isEnabled()) {
logger.write("Syncing total number of fiiles: " + files.length);
}
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.isFile()) {
if (logger.isEnabled()) {
logger.write("Syncing: " + file.getAbsolutePath().toString());
}
String targetFilePath = file.getAbsolutePath().replace(sourceRootAbsolutePath, targetRootAbsolutePath);
File targetFileDir = new File(targetFilePath);
File targetParent = targetFileDir.getParentFile();
if (targetParent != null) {
targetParent.mkdirs();
}
boolean success = copyFile(file.getAbsolutePath(), targetFilePath);
if (!success) {
logger.write("Sync failed: " + file.getAbsolutePath().toString());
}
} else {
moveFiles(file, sourceRootAbsolutePath, targetRootAbsolutePath);
}
}
} else {
if (logger.isEnabled()) {
logger.write("Can't move files. Source is empty.");
}
}
}
// this removes only the app directory from the device to preserve
// any existing files in /files directory on the device
private void executeFullSync(Context context, final File sourceDir) {
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
final File appDir = new File(appPath);
if (appDir.exists()) {
deleteDir(appDir);
moveFiles(sourceDir, sourceDir.getAbsolutePath(), appDir.getAbsolutePath());
}
}
private void executePartialSync(Context context, File sourceDir) {
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
final File appDir = new File(appPath);
if (!appDir.exists()) {
Log.e("TNS", "Application dir does not exists. Partial Sync failed. appDir: " + appPath);
return;
}
if (logger.isEnabled()) {
logger.write("Syncing sourceDir " + sourceDir.getAbsolutePath() + " with " + appDir.getAbsolutePath());
}
moveFiles(sourceDir, sourceDir.getAbsolutePath(), appDir.getAbsolutePath());
}
private void deleteRemovedFiles(File sourceDir, String sourceRootAbsolutePath, String targetRootAbsolutePath) {
if (!sourceDir.exists()) {
if (logger.isEnabled()) {
logger.write("Directory does not exist: " + sourceDir.getAbsolutePath());
}
}
File[] files = sourceDir.listFiles();
if (files != null) {
for (int i = 0; i < files.length; i++) {
File file = files[i];
String targetFilePath = file.getAbsolutePath().replace(sourceRootAbsolutePath, targetRootAbsolutePath);
File targetFile = new File(targetFilePath);
if (file.isFile()) {
if (logger.isEnabled()) {
logger.write("Syncing removed file: " + file.getAbsolutePath().toString());
}
targetFile.delete();
} else {
deleteRemovedFiles(file, sourceRootAbsolutePath, targetRootAbsolutePath);
// this is done so empty folders, if any, are deleted after we're don deleting files.
if (targetFile.listFiles().length == 0) {
targetFile.delete();
}
}
}
}
}
private void executeRemovedSync(final Context context, final File sourceDir) {
String appPath = context.getFilesDir().getAbsolutePath() + "/app";
deleteRemovedFiles(sourceDir, sourceDir.getAbsolutePath(), appPath);
}
private boolean copyFile(String sourceFile, String destinationFile) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(destinationFile, false);
byte[] buffer = new byte[4096];
int read = 0;
while ((read = fis.read(buffer)) != -1) {
fos.write(buffer, 0, read);
}
} catch (FileNotFoundException e) {
logger.write("Error copying file " + sourceFile);
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
return false;
} catch (IOException e) {
logger.write("Error copying file " + sourceFile);
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
return false;
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
}
}
return true;
}
}

View file

@ -1,448 +0,0 @@
package com.tns;
import android.content.Context;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.io.OutputStream;
import java.util.Arrays;
public class NativeScriptSyncServiceSocketImpl {
private static String DEVICE_APP_DIR;
private final Runtime runtime;
private static Logger logger;
private final Context context;
private LocalServerSocketThread localServerThread;
private Thread localServerJavaThread;
public NativeScriptSyncServiceSocketImpl(Runtime runtime, Logger logger, Context context) {
this.runtime = runtime;
NativeScriptSyncServiceSocketImpl.logger = logger;
this.context = context;
DEVICE_APP_DIR = this.context.getFilesDir().getAbsolutePath() + "/app";
}
private class LocalServerSocketThread implements Runnable {
private volatile boolean running;
private final String name;
private LiveSyncWorker livesyncWorker;
private LocalServerSocket deviceSystemSocket;
public LocalServerSocketThread(String name) {
this.name = name;
this.running = false;
}
public void stop() {
this.running = false;
try {
deviceSystemSocket.close();
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
public void run() {
running = true;
try {
deviceSystemSocket = new LocalServerSocket(this.name);
while (running) {
LocalSocket systemSocket = deviceSystemSocket.accept();
livesyncWorker = new LiveSyncWorker(systemSocket);
Thread liveSyncThread = setUpLivesyncThread();
liveSyncThread.start();
}
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
catch (java.security.NoSuchAlgorithmException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
private Thread setUpLivesyncThread() {
Thread livesyncThread = new Thread(livesyncWorker);
livesyncThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.write(String.format("%s(%s): %s", t.getName(), t.getId(), e.toString()));
}
});
livesyncThread.setName("Livesync Thread");
return livesyncThread;
}
@Override
protected void finalize() throws Throwable {
deviceSystemSocket.close();
}
}
public void startServer() {
localServerThread = new LocalServerSocketThread(context.getPackageName() + "-livesync");
localServerJavaThread = new Thread(localServerThread);
localServerJavaThread.setName("Livesync Server Thread");
localServerJavaThread.start();
}
private class LiveSyncWorker implements Runnable {
public static final int OPERATION_BYTE_SIZE = 1;
public static final int HASH_BYTE_SIZE = 16;
public static final int LENGTH_BYTE_SIZE = 1;
public static final int OPERATION_ID_BYTE_SIZE = 32;
public static final int DELETE_FILE_OPERATION = 7;
public static final int CREATE_FILE_OPERATION = 8;
public static final int DO_SYNC_OPERATION = 9;
public static final int ERROR_REPORT_CODE = 1;
public static final int OPERATION_END_NO_REFRESH_REPORT_CODE = 3;
public static final int OPERATION_END_REPORT_CODE = 2;
public static final int REPORT_CODE_SIZE = 1;
public static final int DO_REFRESH_LENGTH = 1;
public static final int DO_REFRESH_VALUE = 1;
public static final String FILE_NAME = "fileName";
public static final String FILE_NAME_LENGTH = FILE_NAME + "Length";
public static final String OPERATION = "operation";
public static final String FILE_CONTENT = "fileContent";
public static final String FILE_CONTENT_LENGTH = FILE_CONTENT + "Length";
public static final int DEFAULT_OPERATION = -1;
private static final String PROTOCOL_VERSION = "0.2.0";
private byte[] handshakeMessage;
private final DigestInputStream input;
private Closeable livesyncSocket;
private OutputStream output;
public LiveSyncWorker(LocalSocket systemSocket) throws IOException, java.security.NoSuchAlgorithmException {
this.livesyncSocket = systemSocket;
MessageDigest md = MessageDigest.getInstance("MD5");
input = new DigestInputStream(systemSocket.getInputStream(), md);
output = systemSocket.getOutputStream();
handshakeMessage = getHandshakeMessage();
}
public void run() {
try {
output.write(handshakeMessage);
output.flush();
} catch (IOException e) {
logger.write(String.format("Error while LiveSyncing: Client socket might be closed!", e.toString()));
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
try {
do {
int operation = getOperation();
if (operation == DELETE_FILE_OPERATION) {
String fileName = getFileName();
validateData();
deleteRecursive(new File(DEVICE_APP_DIR, fileName));
} else if (operation == CREATE_FILE_OPERATION) {
String fileName = getFileName();
int contentLength = getFileContentLength(fileName);
validateData();
byte[] content = getFileContent(fileName, contentLength);
validateData();
createOrOverrideFile(fileName, content);
} else if (operation == DO_SYNC_OPERATION) {
byte[] operationUid = readNextBytes(OPERATION_ID_BYTE_SIZE);
byte doRefresh = readNextBytes(DO_REFRESH_LENGTH)[0];
int doRefreshInt = (int)doRefresh;
int operationReportCode;
validateData();
if(runtime != null && doRefreshInt == DO_REFRESH_VALUE) {
runtime.runScript(new File(NativeScriptSyncServiceSocketImpl.this.context.getFilesDir(), "internal/livesync.js"), false);
operationReportCode = OPERATION_END_REPORT_CODE;
} else {
operationReportCode = OPERATION_END_NO_REFRESH_REPORT_CODE;
}
output.write(getReportMessageBytes(operationReportCode, operationUid));
output.flush();
} else if (operation == DEFAULT_OPERATION) {
logger.write("LiveSync: input stream is empty!");
break;
} else {
throw new IllegalArgumentException(String.format("\nLiveSync: Operation not recognised. Received operation is %s.", operation));
}
} while (true);
} catch (Exception e) {
String message = String.format("Error while LiveSyncing: %s", e.toString());
this.closeWithError(message);
} catch (Throwable e) {
String message = String.format("%s(%s): Error while LiveSyncing.\nOriginal Exception: %s", Thread.currentThread().getName(), Thread.currentThread().getId(), e.toString());
this.closeWithError(message);
}
}
private byte[] getErrorMessageBytes(String message) {
return this.getReportMessageBytes(ERROR_REPORT_CODE, message.getBytes());
}
private byte[] getReportMessageBytes(int reportType, byte[] messageBytes) {
byte[] reportBytes = new byte[]{(byte)reportType};
byte[] combined = new byte[messageBytes.length + REPORT_CODE_SIZE];
System.arraycopy(reportBytes,0,combined, 0, REPORT_CODE_SIZE);
System.arraycopy(messageBytes,0,combined, REPORT_CODE_SIZE, messageBytes.length);
return combined;
}
private byte[] getHandshakeMessage() {
byte[] protocolVersionBytes = PROTOCOL_VERSION.getBytes();
byte[] versionLength = new byte[]{(byte)protocolVersionBytes.length};
byte[] packageNameBytes = context.getPackageName().getBytes();
byte[] combined = new byte[protocolVersionBytes.length + packageNameBytes.length + versionLength.length];
System.arraycopy(versionLength,0,combined, 0, versionLength.length);
System.arraycopy(protocolVersionBytes,0,combined, versionLength.length, protocolVersionBytes.length);
System.arraycopy(packageNameBytes,0,combined,protocolVersionBytes.length + versionLength.length,packageNameBytes.length);
return combined;
}
private void validateData() throws IOException {
MessageDigest messageDigest = input.getMessageDigest();
byte[] digest = messageDigest.digest();
input.on(false);
byte[] inputMD5 = readNextBytes(HASH_BYTE_SIZE);
input.on(true);
if(!Arrays.equals(digest, inputMD5)){
throw new IllegalStateException(String.format("\nLiveSync: Validation of data failed.\nComputed hash: %s\nOriginal hash: %s ", Arrays.toString(digest), Arrays.toString(inputMD5)));
}
}
/*
* Tries to read operation input stream
* If the stream is empty, method returns -1
* */
private int getOperation() {
Integer operation;
byte[] operationBuff = null;
try {
operationBuff = readNextBytes(OPERATION_BYTE_SIZE);
if (operationBuff == null) {
return DEFAULT_OPERATION;
}
operation = Integer.parseInt(new String(operationBuff));
} catch (Exception e) {
if(operationBuff == null){
operationBuff = new byte[]{};
}
throw new IllegalStateException(String.format("\nLiveSync: failed to parse %s. Bytes read: $s %s\nOriginal Exception: %s", OPERATION, Arrays.toString(operationBuff), e.toString()));
}
return operation;
}
private String getFileName() {
byte[] fileNameBuffer;
int fileNameLength = -1;
try {
fileNameLength = getLength();
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: failed to parse %s. \nOriginal Exception: %s", FILE_NAME_LENGTH, e.toString()));
}
if(fileNameLength <= 0) {
throw new IllegalStateException(String.format("\nLiveSync: File name length must be positive number or zero. Provided length: %s.", fileNameLength));
}
try {
fileNameBuffer = readNextBytes(fileNameLength);
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: failed to parse %s.\nOriginal Exception: %s", FILE_NAME, e.toString()));
}
if (fileNameBuffer == null) {
throw new IllegalStateException(String.format("\nLiveSync: Missing %s bytes.", FILE_NAME));
}
String fileName = new String(fileNameBuffer);
if (fileName.trim().length() < fileNameLength) {
logger.write(String.format("WARNING: %s parsed length is less than %s. We read less information than you specified!", FILE_NAME, FILE_NAME_LENGTH));
}
return fileName.trim();
}
private int getFileContentLength(String fileName) throws IllegalStateException {
int contentLength;
try {
contentLength = getLength();
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: failed to read %s for %s.\nOriginal Exception: %s", FILE_CONTENT_LENGTH, fileName, e.toString()));
}
if(contentLength < 0){
throw new IllegalStateException(String.format("\nLiveSync: Content length must be positive number or zero. Provided content length: %s.", contentLength));
}
return contentLength;
}
private byte[] getFileContent(String fileName, int contentLength) throws IllegalStateException {
byte[] contentBuff = null;
try {
if(contentLength > 0) {
contentBuff = readNextBytes(contentLength);
} else if(contentLength == 0){
contentBuff = new byte[]{};
}
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: failed to parse content of file: %s.\nOriginal Exception: %s", fileName, e.toString()));
}
if (contentLength != 0 && contentBuff == null) {
throw new IllegalStateException(String.format("\nLiveSync: Missing %s bytes for file: %s. Did you send %s bytes?", FILE_CONTENT, fileName, contentLength));
}
return contentBuff;
}
private int getLength() {
byte[] lengthBuffer;
int lengthInt;
try {
byte lengthSize = readNextBytes(LENGTH_BYTE_SIZE)[0];
//Cast signed byte to unsigned int
int lengthSizeInt = ((int) lengthSize) & 0xFF;
lengthBuffer = readNextBytes(lengthSizeInt);
if (lengthBuffer == null) {
throw new IllegalStateException(String.format("\nLiveSync: Missing size length bytes."));
}
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: Failed to read size length. \nOriginal Exception: %s", e.toString()));
}
try {
lengthInt = Integer.valueOf(new String(lengthBuffer));
} catch (Exception e) {
throw new IllegalStateException(String.format("\nLiveSync: Failed to parse size length. \nOriginal Exception: %s", e.toString()));
}
return lengthInt;
}
private void createOrOverrideFile(String fileName, byte[] content) throws IOException {
File fileToCreate = prepareFile(fileName);
try {
fileToCreate.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(fileToCreate.getCanonicalPath());
if(runtime != null) {
runtime.lock();
}
fos.write(content);
fos.close();
} catch (Exception e) {
throw new IOException(String.format("\nLiveSync: failed to write file: %s\nOriginal Exception: %s", fileName, e.toString()));
} finally {
if(runtime != null) {
runtime.unlock();
}
}
}
void deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory())
for (File child : fileOrDirectory.listFiles()) {
deleteRecursive(child);
}
fileOrDirectory.delete();
}
private File prepareFile(String fileName) {
File fileToCreate = new File(DEVICE_APP_DIR, fileName);
if (fileToCreate.exists()) {
fileToCreate.delete();
}
return fileToCreate;
}
/*
* Reads next bites from input stream. Bytes read depend on passed parameter.
* */
private byte[] readNextBytes(int size) throws IOException {
byte[] buffer = new byte[size];
int bytesRead = 0;
int bufferWriteOffset = bytesRead;
try {
do {
bytesRead = this.input.read(buffer, bufferWriteOffset, size);
if (bytesRead == -1) {
if (bufferWriteOffset == 0) {
return null;
}
break;
}
size -= bytesRead;
bufferWriteOffset += bytesRead;
} while (size > 0);
} catch (IOException e) {
String message = e.getMessage();
if (message != null && message.equals("Try again")) {
throw new IllegalStateException("Error while LiveSyncing: Read operation timed out.");
} else {
throw e;
}
}
return buffer;
}
private void closeWithError(String message) {
try {
output.write(getErrorMessageBytes(message));
output.flush();
logger.write(message);
this.livesyncSocket.close();
} catch (IOException e) {
if (com.tns.Runtime.isDebuggable()) {
e.printStackTrace();
}
}
}
@Override
protected void finalize() throws Throwable {
this.livesyncSocket.close();
}
}
}

View file

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="com.tns.ErrorReportActivity"
android:theme="@style/Widget.AppCompat.Light.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/toolbar"
android:scrollbarAlwaysDrawVerticalTrack="false">
</androidx.viewpager.widget.ViewPager>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
app:tabIndicatorColor="@color/nativescript_blue"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
tools:tabBackground="@android:color/darker_gray"
android:scrollbarAlwaysDrawVerticalTrack="false"
/>
</RelativeLayout>

View file

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="10dp">
<Button
android:id="@+id/btnCopyException"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@color/nativescript_blue"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:text="Copy to clipboard"
android:textAlignment="textStart"
android:textColor="@android:color/white"
tools:layout_width="match_parent"/>
<LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/btnCopyException"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingBottom="10dp"
android:weightSum="100">
<TextView
android:id="@+id/txtErrorMsg"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="?android:attr/textAppearanceSmall"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"
android:scrollbarAlwaysDrawVerticalTrack="true"/>
</LinearLayout>
</RelativeLayout>

Some files were not shown because too many files have changed in this diff Show more