├── .github
└── workflows
│ ├── compilation-check.yml
│ └── publish.yml
├── .gitignore
├── .idea
└── copyright
│ ├── IceRock.xml
│ └── profiles_settings.xml
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── javascript-build-logic
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── android-app-convention.gradle.kts
│ ├── android-base-convention.gradle.kts
│ ├── android-library-convention.gradle.kts
│ ├── android-publication-convention.gradle.kts
│ ├── detekt-convention.gradle.kts
│ ├── javadoc-stub-convention.gradle.kts
│ ├── multiplatform-library-convention.gradle.kts
│ └── publication-convention.gradle.kts
├── javascript
├── build.gradle.kts
└── src
│ ├── androidMain
│ ├── AndroidManifest.xml
│ └── kotlin
│ │ └── dev
│ │ └── icerock
│ │ └── moko
│ │ └── javascript
│ │ ├── ContextProvider.kt
│ │ ├── ContextProviderDynamic.kt
│ │ └── JavaScriptEngine.kt
│ ├── commonMain
│ └── kotlin
│ │ └── dev
│ │ └── icerock
│ │ └── moko
│ │ └── javascript
│ │ ├── JavaScriptEngine.kt
│ │ ├── JavaScriptEvaluationException.kt
│ │ └── JsType.kt
│ ├── iosMain
│ └── kotlin
│ │ └── dev
│ │ └── icerock
│ │ └── moko
│ │ └── javascript
│ │ └── JavaScriptEngine.kt
│ └── mobileDeviceTest
│ └── kotlin
│ └── dev
│ └── icerock
│ └── moko
│ └── javascript
│ ├── JavaScriptEngineCrossTypesTests.kt
│ ├── JavaScriptEngineJsonTests.kt
│ ├── JavaScriptEngineReuseTests.kt
│ └── JavaScriptEngineSimpleTypesTests.kt
├── sample
├── android-app
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── icerockdev
│ │ │ └── app
│ │ │ └── MainActivity.kt
│ │ └── res
│ │ └── layout
│ │ └── activity_main.xml
├── ios-app
│ ├── Podfile
│ ├── Podfile.lock
│ ├── ios-app.xcodeproj
│ │ ├── project.pbxproj
│ │ └── project.xcworkspace
│ │ │ └── contents.xcworkspacedata
│ ├── ios-app.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── src
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ │ ├── Info.plist
│ │ ├── Resources
│ │ └── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ └── TestViewController.swift
└── mpp-library
│ ├── MultiPlatformLibrary.podspec
│ ├── build.gradle.kts
│ └── src
│ ├── androidMain
│ └── AndroidManifest.xml
│ └── commonMain
│ └── kotlin
│ └── com
│ └── icerockdev
│ └── library
│ └── Calculator.kt
└── settings.gradle.kts
/.github/workflows/compilation-check.yml:
--------------------------------------------------------------------------------
1 | name: KMP library compilation check
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - master
7 | - develop
8 |
9 | jobs:
10 | test:
11 | runs-on: macOS-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v1
15 | - name: Set up JDK 11
16 | uses: actions/setup-java@v1
17 | with:
18 | java-version: 11
19 | - name: Build and test
20 | run: ./gradlew build publishToMavenLocal syncMultiPlatformLibraryDebugFrameworkIosX64
21 | - name: Install pods with kotlin
22 | run: cd sample/ios-app && pod install
23 | - name: build ios sample
24 | run: cd sample/ios-app && set -o pipefail && xcodebuild -scheme ios-app -workspace ios-app.xcworkspace -configuration Debug -sdk iphonesimulator -arch x86_64 build CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO | xcpretty
25 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Create release
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | version:
7 | description: 'Version'
8 | default: '0.1.0'
9 | required: true
10 |
11 | jobs:
12 | publish:
13 | name: Publish library at mavenCentral
14 | runs-on: macOS-latest
15 | env:
16 | OSSRH_USER: ${{ secrets.OSSRH_USER }}
17 | OSSRH_KEY: ${{ secrets.OSSRH_KEY }}
18 | SIGNING_KEY_ID: ${{ secrets.SIGNING_KEYID }}
19 | SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }}
20 | SIGNING_KEY: ${{ secrets.GPG_KEY_CONTENTS }}
21 |
22 | steps:
23 | - uses: actions/checkout@v1
24 | - name: Set up JDK 11
25 | uses: actions/setup-java@v1
26 | with:
27 | java-version: 11
28 | - name: Publish library
29 | run: ./gradlew publish
30 | release:
31 | name: Create release
32 | needs: publish
33 | runs-on: ubuntu-latest
34 | steps:
35 | - name: Create Release
36 | id: create_release
37 | uses: actions/create-release@v1
38 | env:
39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40 | with:
41 | commitish: ${{ github.ref }}
42 | tag_name: release/${{ github.event.inputs.version }}
43 | release_name: ${{ github.event.inputs.version }}
44 | body: "Will be filled later"
45 | draft: true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | .settings
3 | .project
4 | .classpath
5 | .vscode
6 | .idea
7 | build
8 | *.iml
9 | Pods
10 | xcuserdata
11 | local.properties
--------------------------------------------------------------------------------
/.idea/copyright/IceRock.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Do’s and Don’ts
2 |
3 | * **Search tickets before you file a new one.** Add to tickets if you have new information about the issue.
4 | * **Keep tickets short but sweet.** Make sure you include all the context needed to solve the issue. Don't overdo it. Great tickets allow us to focus on solving problems instead of discussing them.
5 | * **Take care of your ticket.** When you spend time to report a ticket with care we'll enjoy fixing it for you.
6 | * **Use [GitHub-flavored Markdown](https://help.github.com/articles/markdown-basics/).** Especially put code blocks and console outputs in backticks (```` ``` ````). That increases the readability. Bonus points for applying the appropriate syntax highlighting.
7 |
8 | ## Bug Reports
9 |
10 | In short, since you are most likely a developer, provide a ticket that you _yourself_ would _like_ to receive.
11 |
12 | First check if you are using the latest library version and Kotlin version before filing a ticket.
13 |
14 | Please include steps to reproduce and _all_ other relevant information, including any other relevant dependency and version information.
15 |
16 | ## Feature Requests
17 |
18 | Please try to be precise about the proposed outcome of the feature and how it
19 | would related to existing features.
20 |
21 |
22 | ## Pull Requests
23 |
24 | We **love** pull requests!
25 |
26 | All contributions _will_ be licensed under the Apache 2 license.
27 |
28 | Code/comments should adhere to the following rules:
29 |
30 | * Names should be descriptive and concise.
31 | * Use four spaces and no tabs.
32 | * Remember that source code usually gets written once and read often: ensure
33 | the reader doesn't have to make guesses. Make sure that the purpose and inner
34 | logic are either obvious to a reasonably skilled professional, or add a
35 | comment that explains it.
36 | * Please add a detailed description.
37 |
38 | If you consistently contribute improvements and/or bug fixes, we're happy to make you a maintainer.
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](http://www.apache.org/licenses/LICENSE-2.0) [ ](https://repo1.maven.org/maven2/dev/icerock/moko/javascript) 
3 |
4 | # Mobile Kotlin javascript
5 | This is a Kotlin MultiPlatform library that allows you to run JavaScript code from common Kotlin code
6 |
7 | ## Table of Contents
8 | - [Features](#features)
9 | - [Requirements](#requirements)
10 | - [Installation](#installation)
11 | - [Usage](#usage)
12 | - [Samples](#samples)
13 | - [Set Up Locally](#set-up-locally)
14 | - [Contributing](#contributing)
15 | - [License](#license)
16 |
17 | ## Features
18 | - Evaluate JavaScript code from Kotlin common code
19 | - Pass objects to JavaScript as global vars
20 |
21 | ## Requirements
22 | - Gradle version 6.0+
23 | - Android API 16+
24 | - iOS version 9.0+
25 |
26 | ## Installation
27 | root build.gradle
28 | ```groovy
29 | allprojects {
30 | repositories {
31 | mavenCentral()
32 | }
33 | }
34 | ```
35 |
36 | project build.gradle
37 | ```groovy
38 | dependencies {
39 | commonMainApi("dev.icerock.moko:javascript:0.3.0")
40 | }
41 | ```
42 |
43 | ## Usage
44 | ```kotlin
45 | val javaScriptEngine = JavaScriptEngine()
46 | val result: JsType = try {
47 | javaScriptEngine.evaluate(
48 | context = emptyMap(),
49 | script = """ "Hello" + "World" """.trimIndent()
50 | )
51 | } catch (ex: JavaScriptEvaluationException) {
52 | // Handle script evaluation error
53 | JsType.Null
54 | }
55 | if (result is JsType.Str) {
56 | println(result.value)
57 | }
58 | ```
59 |
60 | ## Samples
61 | More examples can be found in the [sample directory](sample).
62 |
63 | ## Set Up Locally
64 | - In [javascript directory](javascript) contains `javascript` library;
65 | - In [sample directory](sample) contains samples on android, ios & mpp-library connected to apps.
66 |
67 | ## Contributing
68 | All development (both new features and bug fixes) is performed in `develop` branch. This way `master` sources always contain sources of the most recently released version. Please send PRs with bug fixes to `develop` branch. Fixes to documentation in markdown files are an exception to this rule. They are updated directly in `master`.
69 |
70 | The `develop` branch is pushed to `master` during release.
71 |
72 | More detailed guide for contributers see in [contributing guide](CONTRIBUTING.md).
73 |
74 | ## License
75 |
76 | Copyright 2021 IceRock MAG Inc
77 |
78 | Licensed under the Apache License, Version 2.0 (the "License");
79 | you may not use this file except in compliance with the License.
80 | You may obtain a copy of the License at
81 |
82 | http://www.apache.org/licenses/LICENSE-2.0
83 |
84 | Unless required by applicable law or agreed to in writing, software
85 | distributed under the License is distributed on an "AS IS" BASIS,
86 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
87 | See the License for the specific language governing permissions and
88 | limitations under the License.
89 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | buildscript {
6 | repositories {
7 | mavenCentral()
8 | google()
9 | }
10 | dependencies {
11 | classpath(":javascript-build-logic")
12 | }
13 | }
14 |
15 | allprojects {
16 | plugins.withId("org.gradle.maven-publish") {
17 | group = "dev.icerock.moko"
18 | version = libs.versions.mokoJavascriptVersion.get()
19 | }
20 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx4096m
2 | org.gradle.configureondemand=false
3 | org.gradle.parallel=true
4 |
5 | kotlin.code.style=official
6 | kotlin.native.enableDependencyPropagation=false
7 | kotlin.mpp.enableGranularSourceSetsMetadata=true
8 | kotlin.mpp.enableCompatibilityMetadataVariant=true
9 |
10 | android.useAndroidX=true
11 |
12 | mobile.multiplatform.iosTargetWarning=false
13 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | kotlinTestVersion = "1.6.21"
3 | androidAppCompatVersion = "1.2.0"
4 | materialDesignVersion = "1.0.0"
5 | androidLifecycleVersion = "2.1.0"
6 | androidCoreTestingVersion = "1.3.0"
7 | testJUnitExtVersion = "1.1.2"
8 | quickjsVersion = "0.9.2"
9 | coroutinesVersion = "1.6.0-native-mt"
10 | kotlinxSerializationVersion = "1.3.3"
11 | mokoTestVersion = "0.6.1"
12 | mokoJavascriptVersion = "0.3.0"
13 |
14 |
15 | [libraries]
16 | appCompat = { module = "androidx.appcompat:appcompat", version.ref = "androidAppCompatVersion" }
17 | material = { module = "com.google.android.material:material", version.ref = "materialDesignVersion" }
18 | lifecycle = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "androidLifecycleVersion" }
19 | kotlinTestJUnit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlinTestVersion" }
20 | testRunner = { module = "androidx.test:runner", version.ref = "androidCoreTestingVersion" }
21 | testRules = { module = "androidx.test:rules", version.ref = "androidCoreTestingVersion" }
22 | testJUnitExt = { module = "androidx.test.ext:junit", version.ref = "testJUnitExtVersion" }
23 | testJUnitExtKtx = { module = "androidx.test.ext:junit-ktx", version.ref = "testJUnitExtVersion" }
24 | quickjs = { module = "app.cash.quickjs:quickjs-android", version.ref = "quickjsVersion" }
25 | coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutinesVersion" }
26 | kotlinSerialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationVersion" }
27 | kotlinTest = { module = "org.jetbrains.kotlin:kotlin-test-common", version.ref = "kotlinTestVersion" }
28 | kotlinTestAnnotations = { module = "org.jetbrains.kotlin:kotlin-test-annotations-common", version.ref = "kotlinTestVersion" }
29 | mokoTest = { module = "dev.icerock.moko:test-core", version.ref = "mokoTestVersion" }
30 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/icerockdev/moko-javascript/2aca8b2a6bdebae7f366ea8ca1dece137155bf5f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/javascript-build-logic/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | google()
8 |
9 | gradlePluginPortal()
10 | }
11 |
12 | dependencies {
13 | api("dev.icerock:mobile-multiplatform:0.14.1")
14 | api("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
15 | api("com.android.tools.build:gradle:7.0.1")
16 | api("io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.15.0")
17 | }
18 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/android-app-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("com.android.application")
7 | id("android-base-convention")
8 | id("kotlin-android")
9 | }
10 |
11 | android {
12 | dexOptions {
13 | javaMaxHeapSize = "2g"
14 | }
15 |
16 | buildTypes {
17 | getByName("release") {
18 | isMinifyEnabled = true
19 | proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
20 | }
21 | getByName("debug") {
22 | isDebuggable = true
23 | applicationIdSuffix = ".debug"
24 | }
25 | }
26 |
27 | packagingOptions {
28 | exclude("META-INF/*.kotlin_module")
29 | exclude("META-INF/AL2.0")
30 | exclude("META-INF/LGPL2.1")
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/android-base-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import com.android.build.gradle.BaseExtension
6 |
7 | configure {
8 | compileSdkVersion(30)
9 |
10 | defaultConfig {
11 | minSdkVersion(18)
12 | targetSdkVersion(30)
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/android-library-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("com.android.library")
7 | id("kotlin-android")
8 | id("android-base-convention")
9 | }
10 |
11 | android {
12 | sourceSets.all { java.srcDir("src/$name/kotlin") }
13 | }
14 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/android-publication-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("publication-convention")
7 | }
8 |
9 | afterEvaluate {
10 | publishing.publications {
11 | create("release", MavenPublication::class.java) {
12 | from(components.getByName("release"))
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/detekt-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("io.gitlab.arturbosch.detekt")
7 | }
8 |
9 | detekt {
10 | input.setFrom("src/commonMain/kotlin", "src/androidMain/kotlin", "src/iosMain/kotlin", "src/main/kotlin")
11 | }
12 |
13 | dependencies {
14 | "detektPlugins"("io.gitlab.arturbosch.detekt:detekt-formatting:1.15.0")
15 | }
16 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/javadoc-stub-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("org.gradle.maven-publish")
7 | }
8 |
9 | val javadocJar by tasks.registering(Jar::class) {
10 | archiveClassifier.set("javadoc")
11 | }
12 |
13 | publishing.publications.withType {
14 | // Stub javadoc.jar artifact
15 | artifact(javadocJar.get())
16 | }
17 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/multiplatform-library-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("com.android.library")
7 | id("org.jetbrains.kotlin.multiplatform")
8 | id("android-base-convention")
9 | id("dev.icerock.mobile.multiplatform.android-manifest")
10 | }
11 |
12 | kotlin {
13 | ios()
14 | iosSimulatorArm64()
15 | android {
16 | publishLibraryVariants("release", "debug")
17 | }
18 | sourceSets {
19 | val iosSimulatorArm64Main by getting
20 | val iosSimulatorArm64Test by getting
21 |
22 | val mobileDeviceTest by creating
23 |
24 | val commonTest by getting
25 | val iosMain by getting
26 | val iosTest by getting
27 | val androidAndroidTest by getting
28 |
29 | iosSimulatorArm64Main.dependsOn(iosMain)
30 | iosSimulatorArm64Test.dependsOn(iosTest)
31 |
32 | mobileDeviceTest.dependsOn(commonTest)
33 | iosTest.dependsOn(mobileDeviceTest)
34 | androidAndroidTest.dependsOn(mobileDeviceTest)
35 |
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/javascript-build-logic/src/main/kotlin/publication-convention.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import java.util.Base64
6 |
7 | plugins {
8 | id("javadoc-stub-convention")
9 | id("org.gradle.maven-publish")
10 | id("signing")
11 | }
12 |
13 | publishing {
14 | repositories.maven("https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/") {
15 | name = "OSSRH"
16 |
17 | credentials {
18 | username = System.getenv("OSSRH_USER")
19 | password = System.getenv("OSSRH_KEY")
20 | }
21 | }
22 |
23 | publications.withType {
24 | // Provide artifacts information requited by Maven Central
25 | pom {
26 | name.set("MOKO JavaScript")
27 | description.set("JavaScript code evaluation from common code for Kotlin Multiplatform Mobile")
28 | url.set("https://github.com/icerockdev/moko-javascript")
29 | licenses {
30 | license {
31 | name.set("Apache-2.0")
32 | distribution.set("repo")
33 | url.set("https://github.com/icerockdev/moko-javascript/blob/master/LICENSE.md")
34 | }
35 | }
36 |
37 | developers {
38 | developer {
39 | id.set("Tetraquark")
40 | name.set("Vladislav Areshkin")
41 | email.set("vareshkin@icerockdev.com")
42 | }
43 | developer {
44 | id.set("Dorofeev")
45 | name.set("Andrey Dorofeev")
46 | email.set("adorofeev@icerockdev.com")
47 | }
48 | developer {
49 | id.set("Alex009")
50 | name.set("Aleksey Mikhailov")
51 | email.set("aleksey.mikhailov@icerockdev.com")
52 | }
53 | }
54 |
55 | scm {
56 | connection.set("scm:git:ssh://github.com/icerockdev/moko-javascript.git")
57 | developerConnection.set("scm:git:ssh://github.com/icerockdev/moko-javascript.git")
58 | url.set("https://github.com/icerockdev/moko-javascript")
59 | }
60 | }
61 | }
62 | }
63 |
64 |
65 | signing {
66 | val signingKeyId: String? = System.getenv("SIGNING_KEY_ID")
67 | val signingPassword: String? = System.getenv("SIGNING_PASSWORD")
68 | val signingKey: String? = System.getenv("SIGNING_KEY")?.let { base64Key ->
69 | String(Base64.getDecoder().decode(base64Key))
70 | }
71 | if (signingKeyId != null) {
72 | useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
73 | sign(publishing.publications)
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/javascript/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import org.gradle.api.tasks.testing.logging.TestExceptionFormat
6 | import org.gradle.api.tasks.testing.logging.TestLogEvent
7 |
8 | plugins {
9 | id("multiplatform-library-convention")
10 | id("dev.icerock.mobile.multiplatform.android-manifest")
11 | id("publication-convention")
12 | }
13 |
14 | android {
15 | testOptions.unitTests.isIncludeAndroidResources = true
16 | defaultConfig {
17 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | sourceSets {
21 | getByName("androidTest").java.srcDirs(
22 | file("src/androidAndroidTest/kotlin"),
23 | file("src/mobileDeviceTest/kotlin")
24 | )
25 | }
26 | }
27 |
28 | dependencies {
29 | androidMainImplementation(libs.quickjs)
30 | commonMainImplementation(libs.kotlinSerialization)
31 | commonTestImplementation(libs.kotlinTest)
32 | commonTestImplementation(libs.kotlinTestAnnotations)
33 | commonTestImplementation(libs.mokoTest)
34 | androidTestImplementation(libs.kotlinTestJUnit)
35 | androidTestImplementation(libs.testRunner)
36 | androidTestImplementation(libs.testRules)
37 | androidTestImplementation(libs.testJUnitExt)
38 | androidTestImplementation(libs.testJUnitExtKtx)
39 | }
40 |
41 | tasks.withType {
42 | testLogging {
43 | exceptionFormat = TestExceptionFormat.FULL
44 | events = setOf(
45 | TestLogEvent.SKIPPED,
46 | TestLogEvent.PASSED,
47 | TestLogEvent.FAILED
48 | )
49 | showStandardStreams = true
50 | }
51 | outputs.upToDateWhen { false }
52 | }
53 |
--------------------------------------------------------------------------------
/javascript/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/javascript/src/androidMain/kotlin/dev/icerock/moko/javascript/ContextProvider.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | internal interface ContextProvider {
8 | fun getBool(name: String): Boolean
9 | fun getDouble(name: String): Double
10 |
11 | fun getString(name: String): String
12 |
13 | fun getScript(): String
14 | }
15 |
--------------------------------------------------------------------------------
/javascript/src/androidMain/kotlin/dev/icerock/moko/javascript/ContextProviderDynamic.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2022 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | internal class ContextProviderDynamic : ContextProvider {
8 | var context: Map = emptyMap()
9 | var activeScript: String = ""
10 |
11 | override fun getBool(name: String): Boolean {
12 | return context[name]!!.boolValue()
13 | }
14 |
15 | override fun getDouble(name: String): Double {
16 | return context[name]!!.doubleValue()
17 | }
18 |
19 | override fun getString(name: String): String {
20 | val jsType: JsType = context[name]!!
21 | return when (jsType) {
22 | is JsType.Bool, is JsType.DoubleNum, JsType.Null -> throw IllegalArgumentException()
23 | is JsType.Json -> jsType.value.toString()
24 | is JsType.Str -> jsType.value
25 | }
26 | }
27 |
28 | override fun getScript(): String = activeScript
29 | }
30 |
--------------------------------------------------------------------------------
/javascript/src/androidMain/kotlin/dev/icerock/moko/javascript/JavaScriptEngine.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import app.cash.quickjs.QuickJs
8 | import app.cash.quickjs.QuickJsException
9 | import kotlinx.serialization.SerializationException
10 | import kotlinx.serialization.json.Json
11 | import kotlinx.serialization.json.JsonArray
12 | import kotlinx.serialization.json.JsonElement
13 | import kotlinx.serialization.json.JsonObject
14 |
15 | actual class JavaScriptEngine actual constructor() {
16 | private val quickJs: QuickJs = QuickJs.create()
17 | private val json: Json = Json.Default
18 | private val jsContext: ContextProviderDynamic = ContextProviderDynamic()
19 |
20 | @Volatile
21 | var isClosed = false
22 | private set
23 |
24 | init {
25 | quickJs.set("mokoJsContext", ContextProvider::class.java, jsContext)
26 | quickJs.evaluate(
27 | """
28 | function mokoJavaScriptProcessResult(result) {
29 | if (typeof result === 'object') return JSON.stringify(result);
30 | else if (typeof result === 'array') return JSON.stringify(result);
31 | else return result;
32 | }
33 | """.trimIndent()
34 | )
35 | }
36 |
37 | actual fun setContextObjects(vararg context: Pair) {
38 | val scriptContext: Map = context.toMap()
39 | jsContext.context = scriptContext
40 |
41 | val scriptWithContext: String = buildString {
42 | fillContext(scriptContext)
43 | }
44 | quickJs.evaluate(scriptWithContext)
45 | }
46 |
47 | actual fun evaluate(context: Map, script: String): JsType {
48 | if (isClosed) throw JavaScriptEvaluationException(message = "Engine already closed")
49 |
50 | return try {
51 | internalEvaluate(context, script)
52 | } catch (exception: QuickJsException) {
53 | throw JavaScriptEvaluationException(exception, exception.message)
54 | }
55 | }
56 |
57 | actual fun close() {
58 | if (isClosed) return
59 | quickJs.close()
60 | isClosed = true
61 | }
62 |
63 | private fun internalEvaluate(
64 | context: Map,
65 | script: String
66 | ): JsType {
67 | jsContext.activeScript = script
68 | jsContext.context = context
69 |
70 | val scriptWithContext: String = buildString {
71 | fillContext(context)
72 | append("mokoJavaScriptProcessResult(eval(mokoJsContext.getScript()));")
73 | }
74 | val result: Any? = quickJs.evaluate(scriptWithContext)
75 | return handleQuickJsResult(result)
76 | }
77 |
78 | private fun StringBuilder.fillContext(context: Map) {
79 | context.forEach { (name, jsType) ->
80 | append("const ")
81 | append(name)
82 | append(" = ")
83 | append(
84 | when (jsType) {
85 | is JsType.Bool -> "mokoJsContext.getBool('$name')"
86 | is JsType.DoubleNum -> "mokoJsContext.getDouble('$name')"
87 | is JsType.Json -> "JSON.parse(mokoJsContext.getString('$name'))"
88 | JsType.Null -> "null"
89 | is JsType.Str -> "mokoJsContext.getString('$name')"
90 | }
91 | )
92 | append(";\n")
93 | }
94 | }
95 |
96 | private fun handleQuickJsResult(result: Any?): JsType {
97 | return when (result) {
98 | null -> JsType.Null
99 | is Boolean -> JsType.Bool(result)
100 | is Int -> JsType.DoubleNum(result.toDouble())
101 | is Double -> JsType.DoubleNum(result)
102 | is Float -> JsType.DoubleNum(result.toDouble())
103 | is String -> try {
104 | val jsonElement: JsonElement = json.parseToJsonElement(result)
105 | if (jsonElement is JsonObject || jsonElement is JsonArray) JsType.Json(jsonElement)
106 | else JsType.Str(result)
107 | } catch (ex: SerializationException) {
108 | JsType.Str(result)
109 | } catch (ex: IllegalStateException) {
110 | JsType.Str(result)
111 | }
112 | else -> throw JavaScriptEvaluationException(
113 | message = "Impossible JavaScriptEngine handler state with result [$result]"
114 | )
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/javascript/src/commonMain/kotlin/dev/icerock/moko/javascript/JavaScriptEngine.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | expect class JavaScriptEngine() {
8 | /**
9 | * Evaluate some [script] with external [context].
10 | *
11 | * @throws JavaScriptEvaluationException in case of an error in the engine evaluation or if the
12 | * engine has already been closed.
13 | */
14 | fun evaluate(context: Map, script: String): JsType
15 |
16 | /**
17 | * Set some [context] for all evaluate calls.
18 | */
19 | fun setContextObjects(vararg context: Pair)
20 |
21 | /**
22 | * Closes the engine and releases the allocated memory.
23 | */
24 | fun close()
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/javascript/src/commonMain/kotlin/dev/icerock/moko/javascript/JavaScriptEvaluationException.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | class JavaScriptEvaluationException(
8 | cause: Throwable? = null,
9 | message: String? = null
10 | ) : Exception(message, cause)
11 |
--------------------------------------------------------------------------------
/javascript/src/commonMain/kotlin/dev/icerock/moko/javascript/JsType.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlinx.serialization.json.JsonElement
8 |
9 | sealed class JsType {
10 | data class Bool(override val value: Boolean) : JsType()
11 | data class Str(override val value: String) : JsType()
12 | data class DoubleNum(override val value: Double) : JsType()
13 | data class Json(override val value: JsonElement) : JsType()
14 |
15 | /**
16 | * For "undefined" and "null".
17 | */
18 | object Null : JsType() {
19 | override val value: Any? get() = null
20 | }
21 |
22 | abstract val value: Any?
23 | }
24 |
25 | fun JsType.boolValue(): Boolean = (this as JsType.Bool).value
26 | fun JsType.stringValue(): String = (this as JsType.Str).value
27 | fun JsType.doubleValue(): Double = (this as JsType.DoubleNum).value
28 | fun JsType.jsonValue(): JsonElement = (this as JsType.Json).value
29 | fun JsType.nullValue(): Any? = (this as JsType.Null).let { null }
30 |
--------------------------------------------------------------------------------
/javascript/src/iosMain/kotlin/dev/icerock/moko/javascript/JavaScriptEngine.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlinx.serialization.SerializationException
8 | import kotlinx.serialization.json.Json
9 | import kotlinx.serialization.json.JsonArray
10 | import kotlinx.serialization.json.JsonElement
11 | import kotlinx.serialization.json.JsonNull
12 | import kotlinx.serialization.json.JsonObject
13 | import kotlinx.serialization.json.JsonPrimitive
14 | import platform.Foundation.NSArray
15 | import platform.Foundation.NSDictionary
16 | import platform.Foundation.NSJSONSerialization
17 | import platform.Foundation.NSNull
18 | import platform.Foundation.NSNumber
19 | import platform.Foundation.NSString
20 | import platform.Foundation.NSUTF8StringEncoding
21 | import platform.Foundation.create
22 | import platform.Foundation.dataUsingEncoding
23 | import platform.JavaScriptCore.JSContext
24 | import platform.JavaScriptCore.JSValue
25 | import platform.JavaScriptCore.setObject
26 |
27 | actual class JavaScriptEngine actual constructor() {
28 |
29 | private val jsContext = JSContext().apply {
30 | exceptionHandler = { exceptionContext, exception ->
31 | val message = "\"context = $exceptionContext, exception = $exception\""
32 | throw JavaScriptEvaluationException(cause = null, message = message)
33 | }
34 |
35 | this.evaluateScript(
36 | """
37 | function mokoJavaScriptProcessResult(result) {
38 | if (typeof result === 'object') return JSON.stringify(result);
39 | else if (typeof result === 'array') return JSON.stringify(result);
40 | else return result;
41 | }
42 | """.trimIndent()
43 | )
44 | }
45 |
46 | actual fun setContextObjects(vararg context: Pair) {
47 | context.forEach { (key, value) ->
48 | val contextObject: Any? = prepareValueForJsContext(value)
49 | jsContext.setObject(
50 | `object` = contextObject,
51 | forKeyedSubscript = NSString.create(string = key)
52 | )
53 | }
54 | }
55 |
56 | actual fun evaluate(context: Map, script: String): JsType {
57 | context.forEach { (key, value) ->
58 | jsContext.setObject(
59 | `object` = prepareValueForJsContext(value),
60 | forKeyedSubscript = NSString.create(string = key)
61 | )
62 | }
63 |
64 | val result = jsContext.evaluateScript(script)
65 |
66 | context.forEach { (key, _) ->
67 | jsContext.setObject(
68 | `object` = null,
69 | forKeyedSubscript = NSString.create(string = key)
70 | )
71 | }
72 |
73 | val resultKey = "evaluationResult"
74 | jsContext.setObject(
75 | `object` = result,
76 | forKeyedSubscript = NSString.create(string = resultKey)
77 | )
78 | val formattedResult = jsContext.evaluateScript("mokoJavaScriptProcessResult($resultKey)")
79 | jsContext.setObject(
80 | `object` = null,
81 | forKeyedSubscript = NSString.create(string = resultKey)
82 | )
83 |
84 | return formattedResult?.toMokoJSType() ?: JsType.Null
85 | }
86 |
87 | actual fun close() {
88 | // Nothing to do here
89 | }
90 |
91 | private fun prepareValueForJsContext(valueWrapper: JsType): Any? {
92 | return if (valueWrapper is JsType.Json) valueWrapper.value.getValue()
93 | else valueWrapper.value
94 | }
95 | }
96 |
97 | private fun JsonObject.toNSDictionary(): NSDictionary {
98 | val data = NSString.create(string = this.toString()).dataUsingEncoding(NSUTF8StringEncoding)
99 | ?: return NSDictionary()
100 | return (NSJSONSerialization.JSONObjectWithData(
101 | data = data,
102 | options = 0,
103 | error = null
104 | ) as? NSDictionary) ?: NSDictionary()
105 | }
106 |
107 | private fun JsonArray.toNSArray(): NSArray {
108 | val data = NSString.create(string = this.toString()).dataUsingEncoding(NSUTF8StringEncoding)
109 | ?: return NSArray()
110 | return (NSJSONSerialization.JSONObjectWithData(
111 | data = data,
112 | options = 0,
113 | error = null
114 | ) as? NSArray) ?: NSArray()
115 | }
116 |
117 | private fun JsonElement.getValue(): Any? {
118 | return (this as? JsonObject)?.toNSDictionary()
119 | ?: (this as? JsonArray)?.toNSArray()
120 | ?: (this as? JsonPrimitive)?.content
121 | }
122 |
123 | private fun JSValue.toMokoJSType(): JsType {
124 | val json = Json.Default
125 | return when {
126 | isBoolean -> JsType.Bool(toBool())
127 | isString -> try {
128 | val jsonElement: JsonElement = json.parseToJsonElement(toString_().orEmpty())
129 | if (jsonElement is JsonObject || jsonElement is JsonArray) JsType.Json(jsonElement)
130 | else JsType.Str(toString_().orEmpty())
131 | } catch (ex: SerializationException) {
132 | JsType.Str(toString_().orEmpty())
133 | } catch (ex: IllegalStateException) {
134 | JsType.Str(toString_().orEmpty())
135 | }
136 | isNumber -> JsType.DoubleNum(toDouble())
137 | isNull || isUndefined -> JsType.Null
138 | else -> throw IllegalArgumentException("unknown JSValue type $this")
139 | }
140 | }
141 |
142 | private fun Map.toJson(): JsonObject {
143 | return this.mapKeys {
144 | it.key as String
145 | }.mapValues { it.value.toJsonElement() }
146 | .let { JsonObject(it) }
147 | }
148 |
149 | /**
150 | * @see https://developer.apple.com/documentation/javascriptcore/jsvalue?language=objc#1663421
151 | */
152 | private fun Any?.toJsonElement(): JsonElement {
153 | return when (this) {
154 | null -> JsonNull
155 | is NSNull -> JsonNull
156 | is NSString -> JsonPrimitive(this as String)
157 | is NSNumber -> JsonPrimitive(this.doubleValue)
158 | is NSDictionary -> (this as Map).toJson()
159 | is NSArray -> (this as List<*>).map { it.toJsonElement() }.let { JsonArray(it) }
160 | else -> throw IllegalArgumentException("unknown JSValue type $this")
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/javascript/src/mobileDeviceTest/kotlin/dev/icerock/moko/javascript/JavaScriptEngineCrossTypesTests.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlinx.serialization.json.Json
8 | import kotlinx.serialization.json.encodeToJsonElement
9 | import kotlin.test.AfterTest
10 | import kotlin.test.BeforeTest
11 | import kotlin.test.Ignore
12 | import kotlin.test.Test
13 | import kotlin.test.assertEquals
14 |
15 | class JavaScriptEngineCrossTypesTests {
16 | private lateinit var javaScriptEngine: JavaScriptEngine
17 | private lateinit var context: Map
18 |
19 | @BeforeTest
20 | fun init() {
21 | javaScriptEngine = JavaScriptEngine()
22 |
23 | val list = listOf(5, 15)
24 | val listJson = Json.encodeToJsonElement(list)
25 |
26 | context = mapOf(
27 | "list" to JsType.Json(listJson),
28 | "number" to JsType.DoubleNum(4.0),
29 | "doubleString" to JsType.Str(" Hello ")
30 | )
31 | }
32 |
33 | @AfterTest
34 | fun dispose() {
35 | javaScriptEngine.close()
36 | }
37 |
38 | @Test
39 | fun numberWithNumberSumCheck() {
40 | assertEquals(
41 | expected = JsType.DoubleNum(19.0),
42 | actual = javaScriptEngine.evaluate(context = context, script = "list[1]+number")
43 | )
44 | }
45 |
46 | @Test
47 | fun stringWithNumberSumCheck() {
48 | assertEquals(
49 | actual = JsType.Str(" Hello 5"),
50 | expected = javaScriptEngine.evaluate(context = context, script = "doubleString+list[0]")
51 | )
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/javascript/src/mobileDeviceTest/kotlin/dev/icerock/moko/javascript/JavaScriptEngineJsonTests.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlinx.serialization.json.Json
8 | import kotlinx.serialization.json.encodeToJsonElement
9 | import kotlin.test.AfterTest
10 | import kotlin.test.BeforeTest
11 | import kotlin.test.Test
12 | import kotlin.test.assertEquals
13 |
14 | class JavaScriptEngineJsonTests {
15 | private lateinit var javaScriptEngine: JavaScriptEngine
16 | private lateinit var context: Map
17 |
18 | @BeforeTest
19 | fun init() {
20 | javaScriptEngine = JavaScriptEngine()
21 |
22 | val form = mapOf("selector_1" to "first_value", "selector_2" to "second_value")
23 | val profile = mapOf("email" to "test@test.com")
24 | val formJson = Json.encodeToJsonElement(form)
25 | val profileJson = Json.encodeToJsonElement(profile)
26 |
27 | context = mapOf(
28 | "form" to JsType.Json(formJson),
29 | "profile" to JsType.Json(profileJson)
30 | )
31 | }
32 |
33 | @AfterTest
34 | fun dispose() {
35 | javaScriptEngine.close()
36 | }
37 |
38 | @Test
39 | fun formSelectorCheck() {
40 | assertEquals(
41 | expected = JsType.Bool(true),
42 | actual = javaScriptEngine.evaluate(
43 | context = context,
44 | script = "form.selector_1 == \"first_value\""
45 | )
46 | )
47 | }
48 |
49 | @Test
50 | fun profileEmailCheck() {
51 | assertEquals(
52 | expected = JsType.Bool(true),
53 | actual = javaScriptEngine.evaluate(context = context, script = "profile.email != null")
54 | )
55 | }
56 |
57 | @Test
58 | fun profileStringGet() {
59 | assertEquals(
60 | expected = JsType.Str("test@test.com"),
61 | actual = javaScriptEngine.evaluate(context = context, script = "profile.email")
62 | )
63 | }
64 |
65 | @Test
66 | fun profileNullGet() {
67 | assertEquals(
68 | expected = JsType.Null,
69 | actual = javaScriptEngine.evaluate(context = context, script = "profile.first_name")
70 | )
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/javascript/src/mobileDeviceTest/kotlin/dev/icerock/moko/javascript/JavaScriptEngineReuseTests.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlin.test.AfterTest
8 | import kotlin.test.BeforeTest
9 | import kotlin.test.Test
10 | import kotlin.test.assertEquals
11 |
12 | class JavaScriptEngineReuseTests {
13 | private lateinit var javaScriptEngine: JavaScriptEngine
14 |
15 | @BeforeTest
16 | fun init() {
17 | javaScriptEngine = JavaScriptEngine()
18 | }
19 |
20 | @AfterTest
21 | fun dispose() {
22 | javaScriptEngine.close()
23 | }
24 |
25 | @Test
26 | fun reuseContextTest() {
27 | javaScriptEngine.evaluate(
28 | context = emptyMap(),
29 | """
30 | var firstVal = "hello";
31 | """.trimIndent()
32 | )
33 | val result = javaScriptEngine.evaluate(
34 | context = mapOf("secondVal" to JsType.Str("world")),
35 | """
36 | firstVal + " " + secondVal
37 | """.trimIndent()
38 | )
39 |
40 | assertEquals(
41 | expected = JsType.Str("hello world"),
42 | actual = result
43 | )
44 | }
45 |
46 | @Test
47 | fun reuseGlobalContextTest() {
48 | javaScriptEngine.setContextObjects(
49 | "myTest" to JsType.Str("global")
50 | )
51 | javaScriptEngine.evaluate(
52 | context = emptyMap(),
53 | """
54 | var firstVal = "hello";
55 | """.trimIndent()
56 | )
57 | val result = javaScriptEngine.evaluate(
58 | context = mapOf("secondVal" to JsType.Str("world")),
59 | """
60 | firstVal + " " + myTest + " " + secondVal
61 | """.trimIndent()
62 | )
63 |
64 | assertEquals(
65 | expected = JsType.Str("hello global world"),
66 | actual = result
67 | )
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/javascript/src/mobileDeviceTest/kotlin/dev/icerock/moko/javascript/JavaScriptEngineSimpleTypesTests.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package dev.icerock.moko.javascript
6 |
7 | import kotlinx.serialization.json.JsonArray
8 | import kotlinx.serialization.json.JsonObject
9 | import kotlinx.serialization.json.JsonPrimitive
10 | import kotlinx.serialization.json.jsonObject
11 | import kotlin.test.AfterTest
12 | import kotlin.test.BeforeTest
13 | import kotlin.test.Test
14 | import kotlin.test.assertEquals
15 | import kotlin.test.assertIs
16 | import kotlin.test.assertNull
17 |
18 | class JavaScriptEngineSimpleTypesTests {
19 | private lateinit var javaScriptEngine: JavaScriptEngine
20 |
21 | @BeforeTest
22 | fun init() {
23 | javaScriptEngine = JavaScriptEngine()
24 | }
25 |
26 | @AfterTest
27 | fun dispose() {
28 | javaScriptEngine.close()
29 | }
30 |
31 | @Test
32 | fun integerSumCheck() {
33 | assertEquals(
34 | expected = 101.0,
35 | actual = javaScriptEngine.evaluate(
36 | context = emptyMap(),
37 | script = """
38 | var a = 1 + 100;
39 | a
40 | """.trimIndent()
41 | ).doubleValue()
42 | )
43 | }
44 |
45 | @Test
46 | fun doubleSumCheck() {
47 | assertEquals(
48 | expected = 1.5,
49 | actual = javaScriptEngine.evaluate(
50 | context = emptyMap(),
51 | script = """
52 | var a = 0.5 + 1.0;
53 | a
54 | """.trimIndent()
55 | ).doubleValue()
56 | )
57 | }
58 |
59 | @Test
60 | fun stringReturnCheck() {
61 | assertEquals(
62 | expected = "string",
63 | actual = javaScriptEngine.evaluate(
64 | context = emptyMap(),
65 | script = """
66 | var a = "string";
67 | a
68 | """.trimIndent()
69 | ).stringValue()
70 | )
71 | }
72 |
73 | @Test
74 | fun booleanCheck() {
75 | assertEquals(
76 | expected = false,
77 | actual = javaScriptEngine.evaluate(
78 | context = emptyMap(),
79 | script = """
80 | var a = false == true;
81 | a
82 | """.trimIndent()
83 | ).boolValue()
84 | )
85 | }
86 |
87 | @Test
88 | fun jsonReadCheck() {
89 | val result: JsType = javaScriptEngine.evaluate(
90 | context = mapOf(
91 | "test" to JsType.Json(
92 | JsonObject(
93 | mapOf(
94 | "te" to JsonArray(
95 | listOf(JsonPrimitive("tetete"))
96 | )
97 | )
98 | )
99 | )
100 | ),
101 | script = """
102 | var object = {male:"Ford", model:"Mustang", number:10.1};
103 | Object.assign(object, test);
104 | object;
105 | """.trimIndent()
106 | )
107 | assertIs(result)
108 | assertEquals(
109 | expected = JsonObject(
110 | mapOf(
111 | "number" to JsonPrimitive(10.1),
112 | "model" to JsonPrimitive("Mustang"),
113 | "te" to JsonArray(listOf(JsonPrimitive("tetete"))),
114 | "male" to JsonPrimitive("Ford")
115 | )
116 | ).entries,
117 | actual = result.value.jsonObject.entries
118 | )
119 | }
120 |
121 | @Test
122 | fun undefinedCheck() {
123 | assertNull(
124 | javaScriptEngine.evaluate(
125 | context = emptyMap(),
126 | script = """
127 | var a = undefined
128 | a
129 | """.trimIndent()
130 | ).nullValue()
131 | )
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/sample/android-app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("android-app-convention")
7 | id("kotlin-android")
8 | }
9 |
10 | android {
11 | defaultConfig {
12 | applicationId = "dev.icerock.moko.samples.javascript"
13 |
14 | versionCode = 1
15 | versionName = "0.1.0"
16 | }
17 | }
18 |
19 | dependencies {
20 | implementation(libs.appCompat)
21 | implementation(libs.material)
22 |
23 | implementation(projects.sample.mppLibrary)
24 | }
25 |
--------------------------------------------------------------------------------
/sample/android-app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /opt/android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/android-app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/android-app/src/main/java/com/icerockdev/app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package com.icerockdev.app
6 |
7 | import androidx.appcompat.app.AppCompatActivity
8 |
9 | class MainActivity : androidx.appcompat.app.AppCompatActivity(R.layout.activity_main)
10 |
--------------------------------------------------------------------------------
/sample/android-app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/ios-app/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://cdn.cocoapods.org/'
2 |
3 | # ignore all warnings from all pods
4 | inhibit_all_warnings!
5 |
6 | use_frameworks!
7 | platform :ios, '11.0'
8 |
9 | # workaround for https://github.com/CocoaPods/CocoaPods/issues/8073
10 | # need for correct invalidate of cache MultiPlatformLibrary.framework
11 | install! 'cocoapods', :disable_input_output_paths => true
12 |
13 | target 'ios-app' do
14 | # MultiPlatformLibrary
15 | pod 'MultiPlatformLibrary', :path => '../mpp-library'
16 | end
17 |
--------------------------------------------------------------------------------
/sample/ios-app/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - MultiPlatformLibrary (0.1.0)
3 |
4 | DEPENDENCIES:
5 | - MultiPlatformLibrary (from `../mpp-library`)
6 |
7 | EXTERNAL SOURCES:
8 | MultiPlatformLibrary:
9 | :path: "../mpp-library"
10 |
11 | SPEC CHECKSUMS:
12 | MultiPlatformLibrary: e778b00f0244457dbfd60a071e6dea6822d72d24
13 |
14 | PODFILE CHECKSUM: eabca3897015b3326d5a5f2fac159f4b385f5302
15 |
16 | COCOAPODS: 1.10.0
17 |
--------------------------------------------------------------------------------
/sample/ios-app/ios-app.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 13C620EBD66031F3B1C0EE15 /* Pods_ios_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C62ECD018700C29BD2F127F /* Pods_ios_app.framework */; };
11 | 45D74FCC22BFDDFD00CAB0C8 /* TestViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45D74FCB22BFDDFD00CAB0C8 /* TestViewController.swift */; };
12 | 45F4791D219463C7003D25FA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45F47912219463C7003D25FA /* LaunchScreen.storyboard */; };
13 | 45F4791E219463C7003D25FA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45F47914219463C7003D25FA /* Main.storyboard */; };
14 | 45F47921219463C7003D25FA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 45F4791A219463C7003D25FA /* Assets.xcassets */; };
15 | 45F47922219463C7003D25FA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F4791B219463C7003D25FA /* AppDelegate.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 287627FF1F319065007FA12B /* mokoSampleJavascript.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mokoSampleJavascript.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 3C62ECD018700C29BD2F127F /* Pods_ios_app.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ios_app.framework; sourceTree = BUILT_PRODUCTS_DIR; };
21 | 45964D362282A1FD00C16658 /* mpp-library */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "mpp-library"; path = "../mpp-library"; sourceTree = ""; };
22 | 45D74FCB22BFDDFD00CAB0C8 /* TestViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestViewController.swift; sourceTree = ""; };
23 | 45F47913219463C7003D25FA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
24 | 45F47915219463C7003D25FA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | 45F4791A219463C7003D25FA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
26 | 45F4791B219463C7003D25FA /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
27 | 45F4791C219463C7003D25FA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | A644D2F1C5377C40A53FCD6A /* Pods-ios-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios-app.release.xcconfig"; path = "Pods/Target Support Files/Pods-ios-app/Pods-ios-app.release.xcconfig"; sourceTree = ""; };
29 | DFBDF7D3559D080FDCA444A6 /* Pods-ios-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ios-app.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ios-app/Pods-ios-app.debug.xcconfig"; sourceTree = ""; };
30 | /* End PBXFileReference section */
31 |
32 | /* Begin PBXFrameworksBuildPhase section */
33 | 287627FC1F319065007FA12B /* Frameworks */ = {
34 | isa = PBXFrameworksBuildPhase;
35 | buildActionMask = 2147483647;
36 | files = (
37 | 13C620EBD66031F3B1C0EE15 /* Pods_ios_app.framework in Frameworks */,
38 | );
39 | runOnlyForDeploymentPostprocessing = 0;
40 | };
41 | /* End PBXFrameworksBuildPhase section */
42 |
43 | /* Begin PBXGroup section */
44 | 0C46713DE6750675C174D0A7 /* Pods */ = {
45 | isa = PBXGroup;
46 | children = (
47 | DFBDF7D3559D080FDCA444A6 /* Pods-ios-app.debug.xcconfig */,
48 | A644D2F1C5377C40A53FCD6A /* Pods-ios-app.release.xcconfig */,
49 | );
50 | name = Pods;
51 | sourceTree = "";
52 | };
53 | 287627F61F319065007FA12B = {
54 | isa = PBXGroup;
55 | children = (
56 | 45964D362282A1FD00C16658 /* mpp-library */,
57 | 45F47910219463C7003D25FA /* src */,
58 | 287628001F319065007FA12B /* Products */,
59 | EE1ABB3E79CE541540D3155F /* Frameworks */,
60 | 0C46713DE6750675C174D0A7 /* Pods */,
61 | );
62 | indentWidth = 4;
63 | sourceTree = "";
64 | tabWidth = 4;
65 | usesTabs = 0;
66 | };
67 | 287628001F319065007FA12B /* Products */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 287627FF1F319065007FA12B /* mokoSampleJavascript.app */,
71 | );
72 | name = Products;
73 | sourceTree = "";
74 | };
75 | 45F47910219463C7003D25FA /* src */ = {
76 | isa = PBXGroup;
77 | children = (
78 | 45F47911219463C7003D25FA /* Resources */,
79 | 45F4791A219463C7003D25FA /* Assets.xcassets */,
80 | 45F4791B219463C7003D25FA /* AppDelegate.swift */,
81 | 45F4791C219463C7003D25FA /* Info.plist */,
82 | 45D74FCB22BFDDFD00CAB0C8 /* TestViewController.swift */,
83 | );
84 | path = src;
85 | sourceTree = "";
86 | };
87 | 45F47911219463C7003D25FA /* Resources */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 45F47912219463C7003D25FA /* LaunchScreen.storyboard */,
91 | 45F47914219463C7003D25FA /* Main.storyboard */,
92 | );
93 | path = Resources;
94 | sourceTree = "";
95 | };
96 | EE1ABB3E79CE541540D3155F /* Frameworks */ = {
97 | isa = PBXGroup;
98 | children = (
99 | 3C62ECD018700C29BD2F127F /* Pods_ios_app.framework */,
100 | );
101 | name = Frameworks;
102 | sourceTree = "";
103 | };
104 | /* End PBXGroup section */
105 |
106 | /* Begin PBXNativeTarget section */
107 | 287627FE1F319065007FA12B /* ios-app */ = {
108 | isa = PBXNativeTarget;
109 | buildConfigurationList = 287628111F319065007FA12B /* Build configuration list for PBXNativeTarget "ios-app" */;
110 | buildPhases = (
111 | DDE4C06D580BF457BEDF8D0A /* [CP] Check Pods Manifest.lock */,
112 | 287627FB1F319065007FA12B /* Sources */,
113 | 287627FC1F319065007FA12B /* Frameworks */,
114 | 287627FD1F319065007FA12B /* Resources */,
115 | 02B727FAA6B9D00725C179CA /* [CP] Embed Pods Frameworks */,
116 | );
117 | buildRules = (
118 | );
119 | dependencies = (
120 | );
121 | name = "ios-app";
122 | productName = "ios-app";
123 | productReference = 287627FF1F319065007FA12B /* mokoSampleJavascript.app */;
124 | productType = "com.apple.product-type.application";
125 | };
126 | /* End PBXNativeTarget section */
127 |
128 | /* Begin PBXProject section */
129 | 287627F71F319065007FA12B /* Project object */ = {
130 | isa = PBXProject;
131 | attributes = {
132 | LastSwiftUpdateCheck = 0830;
133 | LastUpgradeCheck = 0830;
134 | ORGANIZATIONNAME = "IceRock Development";
135 | TargetAttributes = {
136 | 287627FE1F319065007FA12B = {
137 | CreatedOnToolsVersion = 8.3.3;
138 | LastSwiftMigration = 0940;
139 | };
140 | };
141 | };
142 | buildConfigurationList = 287627FA1F319065007FA12B /* Build configuration list for PBXProject "ios-app" */;
143 | compatibilityVersion = "Xcode 9.3";
144 | developmentRegion = English;
145 | hasScannedForEncodings = 0;
146 | knownRegions = (
147 | English,
148 | Base,
149 | );
150 | mainGroup = 287627F61F319065007FA12B;
151 | productRefGroup = 287628001F319065007FA12B /* Products */;
152 | projectDirPath = "";
153 | projectRoot = "";
154 | targets = (
155 | 287627FE1F319065007FA12B /* ios-app */,
156 | );
157 | };
158 | /* End PBXProject section */
159 |
160 | /* Begin PBXResourcesBuildPhase section */
161 | 287627FD1F319065007FA12B /* Resources */ = {
162 | isa = PBXResourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | 45F4791E219463C7003D25FA /* Main.storyboard in Resources */,
166 | 45F4791D219463C7003D25FA /* LaunchScreen.storyboard in Resources */,
167 | 45F47921219463C7003D25FA /* Assets.xcassets in Resources */,
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXResourcesBuildPhase section */
172 |
173 | /* Begin PBXShellScriptBuildPhase section */
174 | 02B727FAA6B9D00725C179CA /* [CP] Embed Pods Frameworks */ = {
175 | isa = PBXShellScriptBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | );
179 | inputFileListPaths = (
180 | );
181 | name = "[CP] Embed Pods Frameworks";
182 | outputFileListPaths = (
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | shellPath = /bin/sh;
186 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ios-app/Pods-ios-app-frameworks.sh\"\n";
187 | showEnvVarsInLog = 0;
188 | };
189 | DDE4C06D580BF457BEDF8D0A /* [CP] Check Pods Manifest.lock */ = {
190 | isa = PBXShellScriptBuildPhase;
191 | buildActionMask = 2147483647;
192 | files = (
193 | );
194 | inputFileListPaths = (
195 | );
196 | inputPaths = (
197 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
198 | "${PODS_ROOT}/Manifest.lock",
199 | );
200 | name = "[CP] Check Pods Manifest.lock";
201 | outputFileListPaths = (
202 | );
203 | outputPaths = (
204 | "$(DERIVED_FILE_DIR)/Pods-ios-app-checkManifestLockResult.txt",
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | shellPath = /bin/sh;
208 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
209 | showEnvVarsInLog = 0;
210 | };
211 | /* End PBXShellScriptBuildPhase section */
212 |
213 | /* Begin PBXSourcesBuildPhase section */
214 | 287627FB1F319065007FA12B /* Sources */ = {
215 | isa = PBXSourcesBuildPhase;
216 | buildActionMask = 2147483647;
217 | files = (
218 | 45D74FCC22BFDDFD00CAB0C8 /* TestViewController.swift in Sources */,
219 | 45F47922219463C7003D25FA /* AppDelegate.swift in Sources */,
220 | );
221 | runOnlyForDeploymentPostprocessing = 0;
222 | };
223 | /* End PBXSourcesBuildPhase section */
224 |
225 | /* Begin PBXVariantGroup section */
226 | 45F47912219463C7003D25FA /* LaunchScreen.storyboard */ = {
227 | isa = PBXVariantGroup;
228 | children = (
229 | 45F47913219463C7003D25FA /* Base */,
230 | );
231 | name = LaunchScreen.storyboard;
232 | sourceTree = "";
233 | };
234 | 45F47914219463C7003D25FA /* Main.storyboard */ = {
235 | isa = PBXVariantGroup;
236 | children = (
237 | 45F47915219463C7003D25FA /* Base */,
238 | );
239 | name = Main.storyboard;
240 | sourceTree = "";
241 | };
242 | /* End PBXVariantGroup section */
243 |
244 | /* Begin XCBuildConfiguration section */
245 | 2876280F1F319065007FA12B /* Debug */ = {
246 | isa = XCBuildConfiguration;
247 | buildSettings = {
248 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
249 | CURRENT_PROJECT_VERSION = 0;
250 | DEFINES_MODULE = YES;
251 | SWIFT_VERSION = 4.0;
252 | };
253 | name = Debug;
254 | };
255 | 287628101F319065007FA12B /* Release */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
259 | CURRENT_PROJECT_VERSION = 0;
260 | DEFINES_MODULE = YES;
261 | SWIFT_VERSION = 4.0;
262 | };
263 | name = Release;
264 | };
265 | 287628121F319065007FA12B /* Debug */ = {
266 | isa = XCBuildConfiguration;
267 | baseConfigurationReference = DFBDF7D3559D080FDCA444A6 /* Pods-ios-app.debug.xcconfig */;
268 | buildSettings = {
269 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
270 | CODE_SIGN_IDENTITY = "iPhone Developer";
271 | CODE_SIGN_STYLE = Automatic;
272 | DEVELOPMENT_TEAM = 4VU932NX78;
273 | INFOPLIST_FILE = src/Info.plist;
274 | ONLY_ACTIVE_ARCH = YES;
275 | PRODUCT_BUNDLE_IDENTIFIER = dev.icerock.moko.sample.javascript;
276 | PRODUCT_NAME = mokoSampleJavascript;
277 | PROVISIONING_PROFILE_SPECIFIER = "";
278 | SDKROOT = iphoneos;
279 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
280 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
281 | };
282 | name = Debug;
283 | };
284 | 287628131F319065007FA12B /* Release */ = {
285 | isa = XCBuildConfiguration;
286 | baseConfigurationReference = A644D2F1C5377C40A53FCD6A /* Pods-ios-app.release.xcconfig */;
287 | buildSettings = {
288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
289 | CODE_SIGN_IDENTITY = "iPhone Developer";
290 | CODE_SIGN_STYLE = Automatic;
291 | DEVELOPMENT_TEAM = 4VU932NX78;
292 | INFOPLIST_FILE = src/Info.plist;
293 | ONLY_ACTIVE_ARCH = YES;
294 | PRODUCT_BUNDLE_IDENTIFIER = dev.icerock.moko.sample.javascript;
295 | PRODUCT_NAME = mokoSampleJavascript;
296 | PROVISIONING_PROFILE_SPECIFIER = "";
297 | SDKROOT = iphoneos;
298 | SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
299 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
300 | };
301 | name = Release;
302 | };
303 | /* End XCBuildConfiguration section */
304 |
305 | /* Begin XCConfigurationList section */
306 | 287627FA1F319065007FA12B /* Build configuration list for PBXProject "ios-app" */ = {
307 | isa = XCConfigurationList;
308 | buildConfigurations = (
309 | 2876280F1F319065007FA12B /* Debug */,
310 | 287628101F319065007FA12B /* Release */,
311 | );
312 | defaultConfigurationIsVisible = 0;
313 | defaultConfigurationName = Release;
314 | };
315 | 287628111F319065007FA12B /* Build configuration list for PBXNativeTarget "ios-app" */ = {
316 | isa = XCConfigurationList;
317 | buildConfigurations = (
318 | 287628121F319065007FA12B /* Debug */,
319 | 287628131F319065007FA12B /* Release */,
320 | );
321 | defaultConfigurationIsVisible = 0;
322 | defaultConfigurationName = Release;
323 | };
324 | /* End XCConfigurationList section */
325 | };
326 | rootObject = 287627F71F319065007FA12B /* Project object */;
327 | }
328 |
--------------------------------------------------------------------------------
/sample/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/ios-app/ios-app.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/sample/ios-app/src/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import UIKit
6 |
7 | @UIApplicationMain
8 | class AppDelegate: NSObject, UIApplicationDelegate {
9 |
10 | var window: UIWindow?
11 |
12 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
13 | return true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/sample/ios-app/src/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/sample/ios-app/src/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/sample/ios-app/src/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | moko-javascript
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(BUNDLE_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 0.1.0
21 | CFBundleVersion
22 | 1
23 | LSApplicationCategoryType
24 | public.app-category.developer-tools
25 | LSRequiresIPhoneOS
26 |
27 | NSAppTransportSecurity
28 |
29 | NSAllowsArbitraryLoads
30 |
31 |
32 | NSMainStoryboardFile
33 | Main
34 | UILaunchStoryboardName
35 | LaunchScreen
36 | UIMainStoryboardFile
37 | Main
38 | UIRequiredDeviceCapabilities
39 |
40 | armv7
41 |
42 | UIRequiresFullScreen
43 |
44 | UIStatusBarHidden
45 |
46 | UIStatusBarHidden~ipad
47 |
48 | UIStatusBarStyle
49 | UIStatusBarStyleLightContent
50 | UISupportedInterfaceOrientations
51 |
52 | UIInterfaceOrientationPortrait
53 |
54 | UISupportedInterfaceOrientations~ipad
55 |
56 | UIInterfaceOrientationPortrait
57 | UIInterfaceOrientationLandscapeRight
58 | UIInterfaceOrientationLandscapeLeft
59 | UIInterfaceOrientationPortraitUpsideDown
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/sample/ios-app/src/Resources/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/sample/ios-app/src/Resources/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
48 |
54 |
60 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/sample/ios-app/src/TestViewController.swift:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | import UIKit
6 | import MultiPlatformLibrary
7 |
8 | class TestViewController: UIViewController {
9 |
10 | @IBOutlet private var firstValueTextField: UITextField!
11 | @IBOutlet private var secondValueTextField: UITextField!
12 | @IBOutlet private var resultLabel: UILabel!
13 |
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | }
17 |
18 | @IBAction private func run() {
19 | let result = Calculator().run(a: firstValueTextField.text ?? "", b: secondValueTextField.text ?? "")
20 | if let value = (result as? JsType.Str)?.value {
21 | resultLabel.text = value
22 | }
23 |
24 | if let value = (result as? JsType.DoubleNum)?.value {
25 | resultLabel.text = "\(value)"
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/sample/mpp-library/MultiPlatformLibrary.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'MultiPlatformLibrary'
3 | spec.version = '0.1.0'
4 | spec.homepage = 'Link to a Kotlin/Native module homepage'
5 | spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" }
6 | spec.authors = 'IceRock Development'
7 | spec.license = ''
8 | spec.summary = 'Shared code between iOS and Android'
9 |
10 | spec.vendored_frameworks = "build/cocoapods/framework/#{spec.name}.framework"
11 | spec.libraries = "c++"
12 | spec.module_name = "#{spec.name}_umbrella"
13 |
14 | spec.pod_target_xcconfig = {
15 | 'MPP_LIBRARY_NAME' => 'MultiPlatformLibrary',
16 | 'GRADLE_TASK[sdk=iphonesimulator*][config=*ebug]' => 'syncMultiPlatformLibraryDebugFrameworkIosX64',
17 | 'GRADLE_TASK[sdk=iphonesimulator*][config=*elease]' => 'syncMultiPlatformLibraryReleaseFrameworkIosX64',
18 | 'GRADLE_TASK[sdk=iphoneos*][config=*ebug]' => 'syncMultiPlatformLibraryDebugFrameworkIosArm64',
19 | 'GRADLE_TASK[sdk=iphoneos*][config=*elease]' => 'syncMultiPlatformLibraryReleaseFrameworkIosArm64'
20 | }
21 |
22 | spec.script_phases = [
23 | {
24 | :name => 'Compile Kotlin/Native',
25 | :execution_position => :before_compile,
26 | :shell_path => '/bin/sh',
27 | :script => <<-SCRIPT
28 | MPP_PROJECT_ROOT="$SRCROOT/../../mpp-library"
29 |
30 | MPP_OUTPUT_DIR="$MPP_PROJECT_ROOT/build/cocoapods/framework"
31 | MPP_OUTPUT_NAME="$MPP_OUTPUT_DIR/#{spec.name}.framework"
32 |
33 | "$MPP_PROJECT_ROOT/../../gradlew" -p "$MPP_PROJECT_ROOT" "$GRADLE_TASK"
34 | SCRIPT
35 | }
36 | ]
37 | end
38 |
--------------------------------------------------------------------------------
/sample/mpp-library/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | plugins {
6 | id("com.android.library")
7 | id("android-base-convention")
8 | id("detekt-convention")
9 | id("org.jetbrains.kotlin.multiplatform")
10 | id("dev.icerock.mobile.multiplatform.android-manifest")
11 | id("dev.icerock.mobile.multiplatform.ios-framework")
12 | }
13 |
14 | kotlin {
15 | android()
16 | ios()
17 | }
18 |
19 | dependencies {
20 | commonMainApi(libs.coroutines)
21 | commonMainApi(libs.kotlinSerialization)
22 |
23 | commonMainApi(projects.javascript)
24 | }
25 |
26 | framework {
27 | export(projects.javascript)
28 | }
29 |
--------------------------------------------------------------------------------
/sample/mpp-library/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/sample/mpp-library/src/commonMain/kotlin/com/icerockdev/library/Calculator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | package com.icerockdev.library
6 |
7 | import dev.icerock.moko.javascript.JavaScriptEngine
8 | import dev.icerock.moko.javascript.JsType
9 |
10 | class Calculator {
11 | fun run(a: String, b: String): JsType {
12 | val engine = JavaScriptEngine()
13 | val testScript = "a+b"
14 |
15 | val numberA = a.toDoubleOrNull()
16 | val numberB = b.toDoubleOrNull()
17 |
18 | val context = if (numberA != null && numberB != null) {
19 | mapOf(
20 | "a" to JsType.DoubleNum(numberA),
21 | "b" to JsType.DoubleNum(numberB)
22 | )
23 | } else {
24 | mapOf(
25 | "a" to JsType.Str(a),
26 | "b" to JsType.Str(b)
27 | )
28 | }
29 |
30 | return engine.evaluate(
31 | context = context,
32 | script = testScript
33 | )
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
3 | */
4 |
5 | enableFeaturePreview("VERSION_CATALOGS")
6 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
7 |
8 | dependencyResolutionManagement {
9 | repositories {
10 | mavenCentral()
11 | google()
12 |
13 | jcenter()
14 | }
15 | }
16 |
17 | includeBuild("javascript-build-logic")
18 |
19 | include(":javascript")
20 | include(":sample:android-app")
21 | include(":sample:mpp-library")
22 |
--------------------------------------------------------------------------------