Skip to content

Instantly share code, notes, and snippets.

@shirakaba
Created September 26, 2021 15:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shirakaba/65515633aedc12470b0020926c972506 to your computer and use it in GitHub Desktop.
Save shirakaba/65515633aedc12470b0020926c972506 to your computer and use it in GitHub Desktop.
NativeScript Android generated files
// example/android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.reactnativenativescriptruntime">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:name="com.tns.NativeScriptApplication">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>
// example/android/app/build.gradle
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for NativescriptRuntimeExample: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for NativescriptRuntimeExample, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
project.ext.react = [
enableHermes: false, // clean and rebuild if changing
entryFile: "index.tsx",
]
apply from: "../../node_modules/react-native/react.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
*
* For NativescriptRuntimeExample, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
android {
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.example.reactnativenativescriptruntime"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
implementation project(':reactnativenativescriptruntime')
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
// START NativeScript runtime
apply from: '../nativescript.build.gradle'
// END NativeScript runtime
// example/android/nativescript.build.gradle
import groovy.io.FileType
import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency
import org.gradle.internal.logging.text.StyledTextOutputFactory
import javax.inject.Inject
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
import java.security.MessageDigest
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-parcelize'
}
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/public/nativescript"
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 {
def initialize = { ->
project.ext.extractedDependenciesDir = "${project.buildDir}/exploded-dependencies"
project.ext.aarDependenciesDir = "${project.buildDir}/aar-dependencies"
project.ext.cleanupAllJarsTimestamp = "${project.buildDir}/cleanupAllJars.timestamp"
project.ext.extractAllJarsTimestamp = "${project.buildDir}/extractAllJars.timestamp"
project.ext.PLATFORMS_ANDROID = "android"
project.ext.USER_PROJECT_ROOT = "$rootDir/.."
project.ext.outLogger = services.get(StyledTextOutputFactory).create("colouredOutputLogger")
}
initialize()
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATIONS ///////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
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() ?: 21
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"]
}
// packagingOptions {
// exclude 'META-INF/androidx.fragment_fragment.version'
// }
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
}
}
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()
}
repositories {
google()
mavenCentral()
flatDir{
dirs 'libs/runtime-libs'
}
}
dependencies {
implementation "androidx.multidex:multidex:2.0.1"
implementation "org.apache.commons:commons-io:1.3.2"
def androidXMaterialVersion = "1.1.0"
if (project.hasProperty("androidxMaterialVersion")) {
androidXMaterialVersion = androidxMaterialVersion
}
implementation "com.google.android.material:material:$androidXMaterialVersion"
def useV8Symbols = false
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"])
def kotlinVersion = computeKotlinVersion()
if (enableKotlin) {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
}
}
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// CONFIGURATION PHASE //////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////
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/) {
}
})
////////////////////////////////////////////////////////////////////////////////////
///////////////////////////// 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 moduleDependencies = config.getAllDependencies().withType(ModuleDependency)
moduleDependencies.forEach {
if(it instanceof DefaultProjectDependency){
return
}
def file = project.getConfigurations().detachedConfiguration(it)
file.forEach {
if (it.exists()) {
if (it.path.endsWith(".jar")) {
processJar(it, jars)
}else if (it.path.endsWith(".aar")) {
def destDir = md5(it.path)
def outputDir = new File(Paths.get(aarDependenciesDir, destDir).normalize().toString())
explodeAar(it, outputDir)
outputDir.eachFileRecurse {
if (it.name.endsWith(".jar")) {
processJar(it, jars)
}
}
}
} else {
outLogger.withStyle(Style.Info).println "WARNING: Folder ${it.path} does not exists, the dependent project's classes won't be included in the metadata"
}
}
}
// def dependentProjects = projectDependencies*.dependency
projectDependencies.forEach {
it = it.getDependencyProject()
// 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()}")
// gradle 6.5
if (!jarDir.exists()) {
jarDir = new File("${it.getBuildDir()}/intermediates/runtime_library_classes_jar/${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 crucial 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 {
// Running 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
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)
////////////////////////////////////////////////////////////////////////////////////
////////////////////////////// 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)
// example/android/nativescript.buildscript.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath group: 'commons-io', name: 'commons-io', version: '2.8.0'
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment