├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── buildSrc_ ├── gradle.build.kts ├── settings.gradle.kts └── src │ └── main │ └── kotlin │ └── KotlinJar2NpmPlugin.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proj-androidfront ├── .gitignore ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── kotlin │ │ └── com │ │ └── example │ │ └── androidfront │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── kotlin │ │ └── com │ │ │ └── example │ │ │ └── androidfront │ │ │ └── MainActivity.kt │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── content_main.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── my_backup_rules.xml │ └── test │ └── kotlin │ └── com │ └── example │ └── androidfront │ └── ExampleUnitTest.kt ├── proj-angularfront ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── build.gradle.kts ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── assets │ │ └── .gitkeep │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json ├── tslint.json └── webpack.partial.js ├── proj-backend ├── .gitignore ├── build.gradle.kts └── src │ ├── main │ ├── kotlin │ │ └── ru │ │ │ └── proj │ │ │ └── Application.kt │ └── resources │ │ ├── application.conf │ │ ├── logback.xml │ │ ├── static │ │ └── ktor_logo.svg │ │ └── templates │ │ └── index.ftl │ └── test │ └── kotlin │ └── ru │ └── proj │ └── ApplicationTest.kt ├── proj-common ├── .gitignore ├── build.gradle.kts └── src │ ├── commonMain │ └── kotlin │ │ └── sample │ │ ├── Sample.kt │ │ └── Serializer.kt │ ├── commonTest │ └── kotlin │ │ └── sample │ │ ├── SampleTests.kt │ │ └── SerializerTest.kt │ ├── jsMain │ └── kotlin │ │ └── sample │ │ └── SampleJs.kt │ ├── jsTest │ └── kotlin │ │ └── sample │ │ └── SampleTestsJS.kt │ ├── jvmMain │ └── kotlin │ │ └── sample │ │ └── SampleJvm.kt │ ├── jvmTest │ └── kotlin │ │ └── sample │ │ └── SampleTestsJVM.kt │ ├── linuxMain │ └── kotlin │ │ └── sample │ │ └── SampleLinux.kt │ └── linuxTest │ └── kotlin │ └── sample │ └── SampleTestsNative.kt ├── proj-reactfront ├── build.gradle.kts ├── config-overrides.js ├── gradle.properties ├── package.json └── src │ └── main │ ├── kotlin │ └── ru │ │ └── proj │ │ └── reactfront │ │ ├── app │ │ ├── App.css │ │ └── App.kt │ │ ├── index.css │ │ ├── index.kt │ │ ├── kotlin.svg │ │ ├── logo │ │ ├── Logo.css │ │ ├── Logo.kt │ │ ├── kotlin.svg │ │ └── react.svg │ │ ├── react.svg │ │ └── ticker │ │ └── Ticker.kt │ └── resources │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | **/.git 2 | **/.idea 3 | **/.gradle 4 | **/build 5 | **/*.iml 6 | /.idea 7 | /build 8 | /.git 9 | /*.iml 10 | 11 | **/dist 12 | **/node_modules 13 | /local.properties 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Sergey Okatov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sample multiplatform and multi-frontend Kotlin project 2 | 3 | This progect is aimed to test the usage of the Kotlin multiplatform capabilities to build a 4 | reusable code for as for differenct frontends as for backend. 5 | 6 | The reusable code is deposed in proj-common submodule. It has a description for JVM (jvmMain) and 7 | JS (jsMain) archtectures, while the logics which is common for all architectures are placed in commonMain. 8 | 9 | It us very convenient to place in commonMain interfaces between frontends and backends as well as formatting functions. 10 | 11 | ## Backend 12 | 13 | As a backend framework we use KTOR 14 | 15 | ## Frontend 16 | 17 | As a frontend we have tested the following frameworks: 18 | - Android (JVM platform). Relized fully in **Kotlin**. 19 | - React (JS platform). Realized fully in **Kotlin**. 20 | - Angular (JS platform). Realized in mixture of **Typescript** and 21 | **Kotlin**. 22 | 23 | ## Build system 24 | 25 | Gradle 5.4 Kotlin DSL is used as a build system. For the JS platform frameworks we have used 26 | [Moowork Node Gradle plugin](https://plugins.gradle.org/plugin/com.moowork.node). 27 | 28 | Other promising plugin is [Jetbrains Kotlin Frontend Plugin](https://github.com/Kotlin/kotlin-frontend-plugin). 29 | But it looks abandoned: there are no updates for couple monthes, several merge requests are waiting for acception for 30 | monthes, there are plenty unclosed issues and annoying bugs. 31 | 32 | The experiments in this project motivate us to publish another gradle plugin for kotlin-based 33 | JS frameworks: [kotlin-jar2npm-plugin](https://github.com/svok/kotlin-jar2npm-plugin). 34 | This plugin extracts the content of the KotlinJS JAR-packages to node_modules package repository 35 | and allows KotlinJS code available in all other JavaScript projects. 36 | 37 | ## Installation 38 | 39 | Just clone this project to any folder and build it with Gradle: 40 | 41 | ```bash 42 | git clone https://github.com/svok/kotlin-multiplatform-sample.git 43 | 44 | cd kotlin-multiplatform-sample 45 | 46 | ./gradlew build 47 | ``` 48 | 49 | ## Frontends peculiarities 50 | 51 | ### React 52 | 53 | React frontend is based on official `react-cli` and `react-scripts`. To use these packages 54 | usual `package.json` file is utilized. Kotlin JAR files are evidently not included into that. 55 | They are separately attached to `node_modules` by the gradle script. 56 | 57 | After `gradlew build` the comipled build is placed into `rootProject/proj-reactfront/dist` folder. 58 | It is ready for deployment in production mode. If you need some other modes you can prepare it yourself 59 | with standard `npm run command` (for example, `npm start`) in the folder `rootProject/proj-reactfront`. 60 | 61 | ### Angular 62 | 63 | This is a standard angular-cli project written on Typescript. The external Kotlin library is attached with 64 | the [kotlin-jar2npm-plugin](https://github.com/svok/kotlin-jar2npm-plugin) as well. To work with it, Kotlin 65 | library must be precompiled with the jar2npm task: 66 | ```bash 67 | ./gradlew :proj-angularfront:jar2npm 68 | ``` 69 | After that your IDE (Intelleij Idea in my case) should see that: 70 | ```typescript 71 | import {sample} from 'proj-common'; 72 | ``` 73 | 74 | ## Contribution 75 | 76 | You are welcome to contibute this project. If you want to add some other framework or make other improvements 77 | just clone the project and depose your pull request. 78 | 79 | For any difficulties and bug reports please use the [github issues](https://github.com/svok/kotlin-multiplatform-sample/issues) 80 | section. 81 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | val kotlin_version: String by project 3 | val kotlin_frontend_version: String by project 4 | val android_plugin_version: String by project 5 | 6 | repositories { 7 | jcenter() 8 | google() 9 | mavenCentral() 10 | maven { setUrl("https://dl.bintray.com/kotlin/kotlin-eap") } 11 | maven { setUrl("https://kotlin.bintray.com/kotlinx") } 12 | maven { setUrl("https://dl.bintray.com/jetbrains/kotlin-native-dependencies") } 13 | maven { setUrl("https://dl.bintray.com/svok/jar2npm") } 14 | } 15 | 16 | dependencies { 17 | classpath(kotlin("gradle-plugin", version = kotlin_version)) 18 | classpath(kotlin("serialization", version = kotlin_version)) 19 | classpath(kotlin("frontend-plugin", version = kotlin_frontend_version)) 20 | classpath("com.android.tools.build:gradle:$android_plugin_version") 21 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") 22 | classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlin_version") 23 | } 24 | } 25 | 26 | plugins { 27 | val kotlin_version: String by project 28 | val node_plugin_version: String by project 29 | val docker_plugin_version: String by project 30 | val kotlin_frontend_version: String by project 31 | 32 | kotlin("multiplatform") version kotlin_version apply false 33 | id("maven-publish") 34 | id("com.moowork.node") version node_plugin_version 35 | id("com.bmuschko.docker-remote-api") version docker_plugin_version apply false 36 | id("com.crowdproj.plugins.jar2npm") version "0.1.14" apply false 37 | } 38 | 39 | repositories { 40 | mavenCentral() 41 | } 42 | 43 | val project_group: String by project 44 | val project_version: String by project 45 | group = project_group 46 | version = project_version 47 | 48 | subprojects { 49 | group = project_group 50 | version = project_version 51 | 52 | repositories { 53 | jcenter() 54 | mavenCentral() 55 | maven { setUrl("https://kotlin.bintray.com/kotlinx") } 56 | } 57 | } 58 | 59 | project(":proj-androidfront") { 60 | repositories { 61 | google() 62 | jcenter() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /buildSrc_/gradle.build.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | `java-gradle-plugin` 4 | } 5 | 6 | repositories { 7 | jcenter() 8 | } 9 | 10 | pluginBundle { 11 | // please change these URLs to point to your own website/repository 12 | website = "https://github.com/svok/kotlin-jar2npm-plugin" 13 | vcsUrl = "https://github.com/svok/kotlin-jar2npm-plugin.git" 14 | tags = listOf("jar", "npm", "node", "nodejs", "kotlin", "javascript", "react", "angular") 15 | } 16 | 17 | gradlePlugin { 18 | plugins { 19 | create("jar2npm") { 20 | id = "com.example.jar2npm" 21 | displayName = "Jar2Npm" 22 | description = "Plugin to extract Kotlin JAR JS packages to node_modules folder" 23 | implementationClass = "com.example.jar2npm.KotlinJar2NpmPlugin" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /buildSrc_/settings.gradle.kts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/buildSrc_/settings.gradle.kts -------------------------------------------------------------------------------- /buildSrc_/src/main/kotlin/KotlinJar2NpmPlugin.kt: -------------------------------------------------------------------------------- 1 | import groovy.json.JsonBuilder 2 | import org.gradle.api.tasks.TaskAction 3 | 4 | class KotlinJar2NpmPlugin : Plugin { 5 | 6 | override fun apply(project: Project) { 7 | project { 8 | 9 | project { 10 | plugins { 11 | id("com.moowork.node") version "1.3.1" 12 | } 13 | } 14 | 15 | tasks { 16 | register("myCopyTask", Copy::class) { 17 | group = "sample" 18 | from("build.gradle.kts") 19 | into("build/copy") 20 | } 21 | } 22 | } 23 | } 24 | 25 | @TaskAction 26 | fun run() { 27 | val conf = configurations.testRuntimeClasspath.get() 28 | 29 | val nmReal = project.projectDir.resolve("node_modules").mkDirOrFail() 30 | val nmImported = project.buildDir.resolve("node_modules_imported").mkDirOrFail() 31 | 32 | val allJars = conf 33 | .resolvedConfiguration 34 | .resolvedArtifacts 35 | 36 | val names = allJars 37 | .filter { it.file.isFile && it.file.exists() } 38 | .distinctBy { it.file.canonicalFile.absolutePath } 39 | .map { 40 | val version = it.moduleVersion.id.version 41 | val file = it.file 42 | 43 | val metaName = 44 | zipTree(file).find { fName -> fName.name.endsWith(".meta.js") }?.name ?: return@map "" 45 | val name = metaName.replace("\\.meta\\.js\$".toRegex(), "") 46 | val js = "$name.js" 47 | 48 | val outDir = nmImported.resolve(name).mkDirOrFail() 49 | copy { 50 | from(zipTree(file)) 51 | into(outDir) 52 | } 53 | val packageJson = mapOf( 54 | "name" to name, 55 | "version" to version, 56 | "main" to js, 57 | "_source" to "gradle" 58 | ) 59 | 60 | outDir.resolve("package.json").bufferedWriter().use { out -> 61 | out.appendln(JsonBuilder(packageJson).toPrettyString()) 62 | } 63 | name 64 | } 65 | .filter { it.isNotBlank() } 66 | 67 | 68 | doLast { 69 | names.forEach { name -> 70 | val outDir = nmImported.resolve(name).mkDirOrFail() 71 | nmReal.resolve(name).ensureSymlink(outDir) 72 | } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | project_group=ru.proj 2 | project_version=0.0.1-SNAPSHOT 3 | 4 | kotlin.code.style=official 5 | ktor_version=1.2.6 6 | kotlin_version=1.3.61 7 | #android_plugin_version=3.4.2 8 | android_plugin_version=3.5.2 9 | #coroutine_version=1.2.2 10 | coroutine_version=1.3.3 11 | logback_version=1.2.1 12 | #node_version=10.15.1 13 | node_version=12.14.0 14 | yarn_version=1.21.1 15 | node_plugin_version=1.3.1 16 | docker_plugin_version=4.5.0 17 | shadowjar_version=5.0.0 18 | serialization_version=0.14.0 19 | kotlin_frontend_version=0.0.45 20 | 21 | # Gradle 22 | #org.gradle.logging.level=debug 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Feb 24 13:59:16 YEKT 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.1-all.zip 7 | #distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /proj-androidfront/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /proj-androidfront/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | kotlin("android") 4 | kotlin("android.extensions") 5 | } 6 | 7 | val kotlin_version: String by project 8 | 9 | android { 10 | packagingOptions { 11 | exclude("META-INF/kotlinx-coroutines-core.kotlin_module") 12 | exclude("META-INF/kotlinx-serialization-runtime.kotlin_module") 13 | } 14 | compileSdkVersion(28) 15 | buildToolsVersion = "28.0.3" 16 | defaultConfig { 17 | applicationId = "com.example.androidfront" 18 | minSdkVersion(24) 19 | targetSdkVersion(28) 20 | versionCode = 1 21 | versionName = "1.0" 22 | // testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner" 23 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 24 | } 25 | buildTypes { 26 | getByName("release") { 27 | isMinifyEnabled = false 28 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") 29 | } 30 | } 31 | testBuildType = "debug" 32 | sourceSets { 33 | get("main").java.srcDirs("src/main/kotlin") 34 | get("androidTest").java.srcDirs("src/androidTest/kotlin") 35 | get("test").java.srcDirs("src/test/kotlin") 36 | } 37 | lintOptions { 38 | warning( "InvalidPackage") 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation(project(":proj-common")) 44 | implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) 45 | implementation(kotlin("stdlib-jdk8", kotlin_version)) 46 | implementation(kotlin("test-junit", kotlin_version)) 47 | implementation("com.android.support:appcompat-v7:28.0.0") 48 | implementation("com.android.support.constraint:constraint-layout:1.1.3") 49 | implementation("com.android.support:design:28.0.0") 50 | testImplementation("junit:junit:4.12") 51 | androidTestImplementation("androidx.test:runner:1.1.1") 52 | androidTestImplementation("androidx.test:rules:1.1.1") 53 | androidTestImplementation("androidx.test.ext:junit:1.1.0") 54 | } 55 | 56 | repositories { 57 | mavenCentral() 58 | maven("http://repository.jetbrains.com/all") 59 | } 60 | -------------------------------------------------------------------------------- /proj-androidfront/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /proj-androidfront/src/androidTest/kotlin/com/example/androidfront/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package com.example.androidfront 2 | 3 | import androidx.test.ext.junit.runners.AndroidJUnit4 4 | import androidx.test.platform.app.InstrumentationRegistry 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | /** 10 | * Instrumented test, which will execute on an Android device. 11 | * 12 | * See [testing documentation](http://d.android.com/tools/testing). 13 | */ 14 | @RunWith(AndroidJUnit4::class) 15 | class ExampleInstrumentedTest { 16 | @Test 17 | fun useAppContext() { 18 | // Context of the app under test. 19 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 20 | assertEquals("com.example.androidfront", appContext.packageName) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/kotlin/com/example/androidfront/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.androidfront 2 | 3 | import android.os.Bundle 4 | import android.support.design.widget.Snackbar 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.Menu 7 | import android.view.MenuItem 8 | 9 | import kotlinx.android.synthetic.main.activity_main.* 10 | import sample.* 11 | 12 | class MainActivity : AppCompatActivity() { 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContentView(R.layout.activity_main) 17 | setSupportActionBar(toolbar) 18 | val sample = Sample() 19 | val platform = Platform 20 | 21 | fab.setOnClickListener { view -> 22 | Snackbar.make(view, "Replace with your own action: ${sample.checkMe()} - ${platform.name}", Snackbar.LENGTH_LONG) 23 | // Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) 24 | .setAction("Action", null).show() 25 | } 26 | } 27 | 28 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 29 | // Inflate the menu; this adds items to the action bar if it is present. 30 | menuInflater.inflate(R.menu.menu_main, menu) 31 | return true 32 | } 33 | 34 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 35 | // Handle action bar item clicks here. The action bar will 36 | // automatically handle clicks on the Home/Up button, so long 37 | // as you specify a parent activity in AndroidManifest.xml. 38 | return when (item.itemId) { 39 | R.id.action_settings -> true 40 | else -> super.onOptionsItemSelected(item) 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 50 | 52 | 54 | 56 | 58 | 60 | 62 | 64 | 66 | 68 | 70 | 72 | 74 | 75 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/layout/content_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/svok/kotlin-multiplatform-sample/f55fe8c28998f3796e453e14637cd16dd05b293c/proj-androidfront/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 4 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Sample Android Project 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /proj-androidfront/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 14 |