├── LICENSE ├── README.md ├── android-sample ├── .gitignore ├── README.md ├── app │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── jniLibs │ │ ├── arm64-v8a │ │ │ └── libcryptor_jni.so │ │ ├── armeabi-v7a │ │ │ └── libcryptor_jni.so │ │ ├── x86 │ │ │ └── libcryptor_jni.so │ │ └── x86_64 │ │ │ └── libcryptor_jni.so │ │ ├── kotlin │ │ └── com │ │ │ └── fernandocejas │ │ │ ├── rust │ │ │ └── Cryptor.kt │ │ │ └── sample │ │ │ ├── AndroidApplication.kt │ │ │ ├── MainActivity.kt │ │ │ └── MainViewModel.kt │ │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ └── strings.xml ├── build.gradle.kts ├── gradle.properties ├── gradle │ ├── libs.versions.toml │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts ├── desktop-sample └── README.md ├── ios-sample ├── .gitignore └── README.md ├── rust-library ├── .gitignore ├── .vscode │ └── settings.json ├── Cargo.toml ├── README.md ├── cryptor │ ├── .gitignore │ ├── Cargo.toml │ ├── src │ │ └── lib.rs │ └── tests │ │ └── integration_tests.rs ├── cryptor_c │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── cryptor_global │ ├── Cargo.toml │ └── src │ │ ├── console.rs │ │ ├── io.rs │ │ ├── lib.rs │ │ └── system.rs └── cryptor_jni │ ├── .gitignore │ ├── Cargo.toml │ ├── build.rs │ └── src │ ├── bin │ ├── publish.rs │ └── release.rs │ └── lib.rs └── web-sample ├── .eslintrc.cjs ├── .gitignore ├── .prettierrc.json ├── .tool-versions ├── .vscode └── extensions.json ├── README.md ├── env.d.ts ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico └── img │ ├── logo.svg │ ├── vite.svg │ └── vue.svg ├── src ├── main │ ├── App.vue │ ├── core │ │ ├── core.ts │ │ ├── home │ │ │ ├── components │ │ │ │ └── AppHeader.vue │ │ │ └── views │ │ │ │ ├── AboutView.vue │ │ │ │ └── HomeView.vue │ │ └── router │ │ │ └── index.ts │ ├── features │ │ ├── decryption │ │ │ ├── components │ │ │ │ ├── Decrypt.vue │ │ │ │ └── icons │ │ │ │ │ └── IconTooling.vue │ │ │ ├── decryption.ts │ │ │ └── views │ │ │ │ └── DecryptionView.vue │ │ ├── encryption │ │ │ ├── components │ │ │ │ ├── Encrypt.vue │ │ │ │ └── icons │ │ │ │ │ └── IconTooling.vue │ │ │ ├── encryption.ts │ │ │ └── views │ │ │ │ └── EncryptionView.vue │ │ └── feature.ts │ └── main.ts └── test │ └── core │ └── home │ └── components │ └── AppHeader.spec.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.node.json ├── tsconfig.vitest.json ├── vite.config.ts └── vitest.config.ts /LICENSE: -------------------------------------------------------------------------------- 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. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Architecture: Rust Programming Language Cross-Platform Development 2 | 3 | This repository aims to cover The Rust Programming Language integration with other Platforms: 4 | 5 | - **[ANDROID](android-sample/):** via [Android JNI](https://developer.android.com/training/articles/perf-jni). 6 | - **[iOS](ios-sample/):** via C++. 7 | - **[WEB](web-sample/):** via WebAssembly. 8 | - **[DESKTOP](desktop-sample/):** via [Tauri](https://tauri.app/). 9 | 10 | At the moment ONLY the Android Part is done: 11 | 12 |

13 | rust-cross-platform-project-overview 14 |

15 | 16 | 17 | # How to use this repo 18 | 19 | Each sub-project contains proper README files with information and instructions for local development and project running. 20 | 21 | A bunch of blog posts are worth reading with deeper explanations: 22 | 23 | - [Rust cross-platform... The Android part...](https://fernandocejas.com/blog/engineering/2023-07-27-rust-cross-platform-android/). 24 | - [Rust cross-platform... The iOS part...](). 25 | - [Rust cross-platform... The Web part...](). 26 | 27 | # TODOs 28 | 29 | - [ ] iOS Application (WIP) 30 | - [ ] Web App using WASM: **PR Accepted** 31 | - [ ] Rust CLI Application: **PR Accepted** 32 | - [ ] Rust Desktop Application: **PR Accepted** 33 | 34 | ## License 35 | 36 | Copyright 2023 Fernando Cejas 37 | 38 | Licensed under the Apache License, Version 2.0 (the "License"); 39 | you may not use this file except in compliance with the License. 40 | You may obtain a copy of the License at 41 | 42 | http://www.apache.org/licenses/LICENSE-2.0 43 | 44 | Unless required by applicable law or agreed to in writing, software 45 | distributed under the License is distributed on an "AS IS" BASIS, 46 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 47 | See the License for the specific language governing permissions and 48 | limitations under the License. 49 | 50 | 51 | ![https://fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 52 | 53 | Buy Me A Coffee 54 | -------------------------------------------------------------------------------- /android-sample/.gitignore: -------------------------------------------------------------------------------- 1 | # Windows thumbnail db 2 | Thumbs.db 3 | 4 | # OSX files 5 | .DS_Store 6 | 7 | 8 | # Built application files 9 | *.apk 10 | *.aar 11 | *.ap_ 12 | *.aab 13 | 14 | # Files for the ART/Dalvik VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # Generated files 21 | bin/ 22 | gen/ 23 | out/ 24 | # Uncomment the following line in case you need and you don't have the release build type files in your app 25 | # release/ 26 | 27 | # Gradle files 28 | .gradle/ 29 | build/ 30 | 31 | # Local configuration file (sdk path, etc) 32 | local.properties 33 | 34 | # Proguard folder generated by Eclipse 35 | proguard/ 36 | 37 | # Log Files 38 | *.log 39 | 40 | # Android Studio Navigation editor temp files 41 | .navigation/ 42 | 43 | # Android Studio captures folder 44 | captures/ 45 | 46 | # IntelliJ 47 | .idea/ 48 | *.iml 49 | .idea/workspace.xml 50 | .idea/tasks.xml 51 | .idea/gradle.xml 52 | .idea/assetWizardSettings.xml 53 | .idea/dictionaries 54 | .idea/libraries 55 | # Android Studio 3 in .gitignore file. 56 | .idea/caches 57 | .idea/modules.xml 58 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you 59 | .idea/navEditor.xml 60 | 61 | # Keystore files 62 | # Uncomment the following lines if you do not want to check your keystore files in. 63 | #*.jks 64 | #*.keystore 65 | 66 | # External native build folder generated in Android Studio 2.2 and later 67 | .externalNativeBuild 68 | .cxx/ 69 | 70 | # Google Services (e.g. APIs or Firebase) 71 | # google-services.json 72 | 73 | # Freeline 74 | freeline.py 75 | freeline/ 76 | freeline_project_description.json 77 | 78 | # fastlane 79 | fastlane/report.xml 80 | fastlane/Preview.html 81 | fastlane/screenshots 82 | fastlane/test_output 83 | fastlane/readme.md 84 | 85 | # Version control 86 | vcs.xml 87 | 88 | # lint 89 | lint/intermediates/ 90 | lint/generated/ 91 | lint/outputs/ 92 | lint/tmp/ 93 | # lint/reports/ 94 | -------------------------------------------------------------------------------- /android-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Rust Cross Platform Development: Android Sample 2 | 3 | In order to **get started,** please refer to the the following **article/post** I have written: 4 | 5 | - [Rust cross-platform... The Android part...](https://fernandocejas.com/blog/engineering/2023-07-27-rust-cross-platform-android/). 6 | 7 | ## The Idea 8 | 9 | **A picture worth a thousand words!** Here is a summary of what this repo tries to accomplish: 10 | 11 |

12 | rust-cross-platform-project-overview 13 |

14 | 15 | And here the **implemantion details:** 16 | 17 |

18 | rust-cross-platform-project-overview 19 |

20 | 21 | ### Running this project 22 | 23 | 1. Install the [Android SDK](https://developer.android.com/studio). 24 | 2. Install the [Android NDK](https://developer.android.com/ndk/). 25 | 3. Open Android Studio and import the `build.gradle.kts` file as a new project. 26 | 4. Run the App. 27 | 28 | ### Local Development 29 | 30 | - If you want to **re-build the rust part,** please go to the [`rust-library`](../rust-library) folder and check the [available commands and documentation](../rust-library#cryptor_jni) over there. 31 | 32 | ## License 33 | 34 | Copyright 2023 Fernando Cejas 35 | 36 | Licensed under the Apache License, Version 2.0 (the "License"); 37 | you may not use this file except in compliance with the License. 38 | You may obtain a copy of the License at 39 | 40 | http://www.apache.org/licenses/LICENSE-2.0 41 | 42 | Unless required by applicable law or agreed to in writing, software 43 | distributed under the License is distributed on an "AS IS" BASIS, 44 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 45 | See the License for the specific language governing permissions and 46 | limitations under the License. 47 | 48 | 49 | ![https://fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 50 | 51 | Buy Me A Coffee 52 | -------------------------------------------------------------------------------- /android-sample/app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | class AppConfig { 4 | val id = "com.fernandocejas.sample" 5 | val javaVersion = JavaVersion.VERSION_17 6 | 7 | val compileSdk = libs.versions.compileSdk.get().toInt() 8 | val minSdk = libs.versions.minSdk.get().toInt() 9 | val targetSdk = libs.versions.targetSdk.get().toInt() 10 | } 11 | 12 | 13 | plugins { 14 | alias(libs.plugins.android.application) 15 | alias(libs.plugins.kotlin.android) 16 | } 17 | 18 | android { 19 | val appConfig = AppConfig() 20 | 21 | namespace = appConfig.id 22 | compileSdk = appConfig.compileSdk 23 | 24 | defaultConfig { 25 | applicationId = appConfig.id 26 | 27 | minSdk = appConfig.minSdk 28 | targetSdk = appConfig.targetSdk 29 | versionCode = 1 30 | versionName = "1.0" 31 | 32 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 33 | 34 | ndk { 35 | // Specifies the ABI configurations of your native 36 | // libraries Gradle should build and package with your APK. 37 | // Here is a list of supported ABIs: 38 | // https://developer.android.com/ndk/guides/abis 39 | abiFilters.addAll( 40 | setOf( 41 | "armeabi-v7a", 42 | "arm64-v8a", 43 | "x86", 44 | "x86_64" 45 | ) 46 | ) 47 | } 48 | } 49 | 50 | compileOptions { 51 | sourceCompatibility = appConfig.javaVersion 52 | targetCompatibility = appConfig.javaVersion 53 | } 54 | 55 | kotlinOptions { 56 | jvmTarget = appConfig.javaVersion.toString() 57 | } 58 | 59 | buildFeatures { 60 | // https://developer.android.com/jetpack/compose/setup 61 | compose = true 62 | } 63 | 64 | composeOptions { 65 | // https://developer.android.com/jetpack/androidx/releases/compose-kotlin 66 | kotlinCompilerExtensionVersion = "1.4.8" 67 | } 68 | 69 | buildTypes { 70 | getByName("debug") { 71 | isMinifyEnabled = false 72 | } 73 | getByName("release") { 74 | isMinifyEnabled = true 75 | } 76 | } 77 | } 78 | 79 | dependencies { 80 | implementation(libs.kotlin.stdlib.jdk8) 81 | implementation(libs.kotlinx.coroutines.core) 82 | implementation(libs.kotlinx.coroutines.android) 83 | implementation(libs.android.core.ktx) 84 | implementation(libs.android.appcompat) 85 | 86 | // Jetpack Compose 87 | // https://developer.android.com/jetpack/compose/setup#kotlin_1 88 | val composeBom = platform(libs.androidx.compose.bom) 89 | implementation(composeBom) 90 | androidTestImplementation(composeBom) 91 | 92 | // Livedata 93 | implementation(libs.androidx.compose.runtime.livedata) 94 | 95 | // Material Design 3 96 | implementation(libs.androidx.compose.material3) 97 | implementation(libs.androidx.compose.material3.window.size) 98 | 99 | // Compose Activity Integration 100 | implementation(libs.androidx.activty.compose) 101 | 102 | // Android Studio Preview support 103 | implementation(libs.androidx.compose.ui.tooling.preview) 104 | implementation(libs.androidx.compose.ui.tooling) 105 | } 106 | -------------------------------------------------------------------------------- /android-sample/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android-sample/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android-sample/app/src/main/jniLibs/arm64-v8a/libcryptor_jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/jniLibs/arm64-v8a/libcryptor_jni.so -------------------------------------------------------------------------------- /android-sample/app/src/main/jniLibs/armeabi-v7a/libcryptor_jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/jniLibs/armeabi-v7a/libcryptor_jni.so -------------------------------------------------------------------------------- /android-sample/app/src/main/jniLibs/x86/libcryptor_jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/jniLibs/x86/libcryptor_jni.so -------------------------------------------------------------------------------- /android-sample/app/src/main/jniLibs/x86_64/libcryptor_jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/jniLibs/x86_64/libcryptor_jni.so -------------------------------------------------------------------------------- /android-sample/app/src/main/kotlin/com/fernandocejas/rust/Cryptor.kt: -------------------------------------------------------------------------------- 1 | package com.fernandocejas.rust 2 | 3 | /** 4 | * Helper that acts as an interface between native 5 | * code (in this case Rust via JNI) and Kotlin. 6 | * 7 | * By convention the function signatures should respect 8 | * the original ones from Rust via JNI Project. 9 | */ 10 | class Cryptor { 11 | 12 | /** 13 | * Encrypt a string. 14 | * 15 | * This is an external call to Rust using 16 | * the Java Native Interface (JNI). 17 | * 18 | * @link https://developer.android.com/ndk/samples/sample_hellojni 19 | */ 20 | @Throws(IllegalArgumentException::class) 21 | external fun encrypt(string: String): String 22 | 23 | /** 24 | * Decrypt a string. 25 | * 26 | * This is an external call to Rust using 27 | * the Java Native Interface (JNI). 28 | * 29 | * @link https://developer.android.com/ndk/samples/sample_hellojni 30 | */ 31 | @Throws(IllegalArgumentException::class) 32 | external fun decrypt(string: String): String 33 | } 34 | -------------------------------------------------------------------------------- /android-sample/app/src/main/kotlin/com/fernandocejas/sample/AndroidApplication.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.sample 17 | 18 | import android.app.Application 19 | 20 | class AndroidApplication : Application() { 21 | 22 | override fun onCreate() { 23 | super.onCreate() 24 | loadJNILibraries() 25 | } 26 | 27 | private fun loadJNILibraries() { 28 | /** 29 | * Loads the Crypto C++/Rust (via JNI) Library. 30 | * 31 | * IMPORTANT: 32 | * The name passed as argument () maps to the 33 | * original library name in our Rust project. 34 | */ 35 | System.loadLibrary("cryptor_jni") 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /android-sample/app/src/main/kotlin/com/fernandocejas/sample/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2020 Fernando Cejas Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.fernandocejas.sample 17 | 18 | import android.os.Bundle 19 | import androidx.activity.compose.setContent 20 | import androidx.activity.viewModels 21 | import androidx.appcompat.app.AppCompatActivity 22 | import androidx.compose.foundation.layout.Arrangement 23 | import androidx.compose.foundation.layout.Column 24 | import androidx.compose.foundation.layout.Row 25 | import androidx.compose.foundation.layout.Spacer 26 | import androidx.compose.foundation.layout.fillMaxSize 27 | import androidx.compose.foundation.layout.height 28 | import androidx.compose.foundation.layout.padding 29 | import androidx.compose.material3.Button 30 | import androidx.compose.material3.CenterAlignedTopAppBar 31 | import androidx.compose.material3.ExperimentalMaterial3Api 32 | import androidx.compose.material3.MaterialTheme 33 | import androidx.compose.material3.Surface 34 | import androidx.compose.material3.Text 35 | import androidx.compose.material3.TextField 36 | import androidx.compose.material3.TopAppBarDefaults 37 | import androidx.compose.runtime.Composable 38 | import androidx.compose.runtime.State 39 | import androidx.compose.runtime.getValue 40 | import androidx.compose.runtime.livedata.observeAsState 41 | import androidx.compose.runtime.mutableStateOf 42 | import androidx.compose.runtime.remember 43 | import androidx.compose.runtime.setValue 44 | import androidx.compose.ui.Alignment 45 | import androidx.compose.ui.Modifier 46 | import androidx.compose.ui.graphics.Color 47 | import androidx.compose.ui.res.stringResource 48 | import androidx.compose.ui.unit.dp 49 | import androidx.core.view.WindowCompat 50 | 51 | @OptIn(ExperimentalMaterial3Api::class) 52 | class MainActivity : AppCompatActivity() { 53 | 54 | private val viewModel: MainViewModel by viewModels() 55 | 56 | override fun onCreate(savedInstanceState: Bundle?) { 57 | super.onCreate(savedInstanceState) 58 | 59 | // Turn off the decor fitting system windows, which allows 60 | // us to handle insets, including IME animations. 61 | WindowCompat.setDecorFitsSystemWindows(window, false) 62 | 63 | setContent { 64 | MaterialTheme { 65 | Surface( 66 | modifier = Modifier.fillMaxSize(), 67 | color = MaterialTheme.colorScheme.background 68 | ) { 69 | Column(modifier = Modifier.fillMaxSize()) { 70 | MainScreenComponent() 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | @Composable 78 | fun MainScreenComponent() { 79 | TopBarComponent() 80 | Column( 81 | modifier = Modifier 82 | .fillMaxSize() 83 | .padding(top = 50.dp), 84 | horizontalAlignment = Alignment.CenterHorizontally, 85 | verticalArrangement = Arrangement.Top, 86 | ) { 87 | EncryptDecryptComponent( 88 | observableState = viewModel.encryptedStringResult.observeAsState(initial = ""), 89 | textFieldLabel = stringResource(id = R.string.txt_encrypt_label_hint), 90 | buttonText = stringResource(id = R.string.txt_encrypt), 91 | buttonClickFn = viewModel.encryptString, 92 | ) 93 | Spacer(modifier = Modifier.height(height = 50.dp)) 94 | EncryptDecryptComponent( 95 | observableState = viewModel.decryptedStringResult.observeAsState(initial = ""), 96 | textFieldLabel = stringResource(id = R.string.txt_decrypt_label_hint), 97 | buttonText = stringResource(id = R.string.txt_decrypt), 98 | buttonClickFn = viewModel.decryptString, 99 | ) 100 | } 101 | } 102 | 103 | @Composable 104 | fun TopBarComponent(title: String = stringResource(id = R.string.app_name)) { 105 | CenterAlignedTopAppBar( 106 | title = { 107 | Text( 108 | text = title, 109 | color = MaterialTheme.colorScheme.background, 110 | ) 111 | }, 112 | colors = TopAppBarDefaults.topAppBarColors( 113 | containerColor = MaterialTheme.colorScheme.primary 114 | ) 115 | ) 116 | } 117 | 118 | @Composable 119 | fun EncryptDecryptComponent( 120 | observableState: State, 121 | textFieldLabel: String, 122 | buttonText: String, 123 | buttonClickFn: (String) -> Unit, 124 | ) { 125 | var textToEncryptDecrypt by remember { mutableStateOf("") } 126 | val encryptionDecryptionResult = observableState.value 127 | 128 | TextField( 129 | value = textToEncryptDecrypt, 130 | onValueChange = { textToEncryptDecrypt = it }, 131 | label = { Text(textFieldLabel) } 132 | ) 133 | 134 | if (encryptionDecryptionResult.isNotBlank()) { 135 | Text( 136 | text = encryptionDecryptionResult, 137 | modifier = Modifier.padding(top = 8.dp, bottom = 8.dp), 138 | style = MaterialTheme.typography.bodyLarge 139 | ) 140 | } 141 | 142 | Spacer(modifier = Modifier.height(height = 5.dp)) 143 | 144 | Row { 145 | Button( 146 | onClick = { buttonClickFn(textToEncryptDecrypt) }, 147 | ) { 148 | Text(text = buttonText) 149 | } 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /android-sample/app/src/main/kotlin/com/fernandocejas/sample/MainViewModel.kt: -------------------------------------------------------------------------------- 1 | package com.fernandocejas.sample 2 | 3 | import androidx.lifecycle.LiveData 4 | import androidx.lifecycle.MutableLiveData 5 | import androidx.lifecycle.ViewModel 6 | import com.fernandocejas.rust.Cryptor 7 | 8 | /** 9 | * Used to communicate between screens. 10 | */ 11 | class MainViewModel : ViewModel() { 12 | 13 | /** 14 | * TODO: Just for Learning Purpose. 15 | * 16 | * This collaborator should be passed as 17 | * a constructor argument of the 18 | * [ViewModel]. 19 | * 20 | * @link https://fernandocejas.com/blog/engineering/2019-05-08-architecting-android-reloaded/ 21 | */ 22 | private val cryptor = Cryptor() 23 | 24 | // Encryption 25 | private val _encryptedStringResult = MutableLiveData() 26 | val encryptedStringResult: LiveData = _encryptedStringResult 27 | 28 | // Decryption 29 | private val _decryptedStringResult = MutableLiveData() 30 | val decryptedStringResult: LiveData = _decryptedStringResult 31 | 32 | val encryptString: (String) -> Unit = { 33 | _encryptedStringResult.value = cryptor.encrypt(it) 34 | } 35 | 36 | val decryptString: (String) -> Unit = { 37 | /** 38 | * TODO: Just for Learning Purpose. 39 | * 40 | * Proper handle exceptions and failure. 41 | */ 42 | val decryptionResult = cryptor.decrypt(it) 43 | when { 44 | decryptionResult.isNotBlank() -> _decryptedStringResult.value = decryptionResult 45 | else -> _decryptedStringResult.value = "Invalid Base64 String!!!" 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /android-sample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | 31 | -------------------------------------------------------------------------------- /android-sample/app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android-sample/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Rust on Android - Cryptor 3 | 4 | Encrypt 5 | Text to ENCRYPT 6 | 7 | Decrypt 8 | Text to DECRYPT 9 | 10 | Field cannot be EMPTY 11 | 12 | -------------------------------------------------------------------------------- /android-sample/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | /** 3 | * Use `apply false` in the top-level build.gradle file to add a Gradle 4 | * plugin as a build dependency but not apply it to the current (root) 5 | * project. Don't use `apply false` in sub-projects. For more information, 6 | * see Applying external plugins with same version to subprojects. 7 | */ 8 | alias(libs.plugins.android.application) apply false 9 | alias(libs.plugins.kotlin.android) apply false 10 | } 11 | -------------------------------------------------------------------------------- /android-sample/gradle.properties: -------------------------------------------------------------------------------- 1 | #Gradle Properties 2 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 -XX:MaxPermSize=512m -Xmx4608M 3 | org.gradle.parallel=true 4 | org.gradle.configureondemand=true 5 | 6 | #Application Properties 7 | kotlin.incremental=true 8 | android.useAndroidX=true 9 | android.enableJetifier=true 10 | kotlin.code.style=official 11 | -------------------------------------------------------------------------------- /android-sample/gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # sdk ----------- 3 | compileSdk = "33" 4 | minSdk = "29" 5 | targetSdk = "33" 6 | # kotlin --------- 7 | kotlin = "1.8.22" 8 | kotlinCoroutines = "1.7.2" 9 | # android -------- 10 | ktx = "1.10.1" 11 | appCompat = "1.6.1" 12 | materialDesign = "1.1.1" 13 | composeBom = "2023.05.01" 14 | activityCompose = "1.7.2" 15 | liveData = "1.4.3" 16 | # plugings ------- 17 | androidGradlePlugin = "8.0.2" 18 | 19 | 20 | [libraries] 21 | # dependencies --- 22 | kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } 23 | kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinCoroutines" } 24 | kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinCoroutines" } 25 | android-core-ktx = { module = "androidx.core:core-ktx", version.ref = "ktx" } 26 | android-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appCompat" } 27 | androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "composeBom" } 28 | androidx-compose-runtime-livedata = { module = "androidx.compose.runtime:runtime-livedata", version.ref = "liveData" } 29 | androidx-compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "materialDesign" } 30 | androidx-compose-material3-window-size = { module = "androidx.compose.material3:material3-window-size-class", version.ref = "materialDesign" } 31 | androidx-activty-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } 32 | 33 | # tooling -------- 34 | androidx-compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" } 35 | androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } 36 | 37 | 38 | [plugins] 39 | android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } 40 | kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } 41 | -------------------------------------------------------------------------------- /android-sample/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/android-sample/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android-sample/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /android-sample/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /android-sample/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /android-sample/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("UnstableApiUsage") 2 | 3 | pluginManagement { 4 | /** 5 | * The pluginManagement {repositories {...}} block configures the 6 | * repositories Gradle uses to search or download the Gradle plugins and 7 | * their transitive dependencies. Gradle pre-configures support for remote 8 | * repositories such as JCenter, Maven Central, and Ivy. You can also use 9 | * local repositories or define your own remote repositories. The code below 10 | * defines the Gradle Plugin Portal, Google's Maven repository, 11 | * and the Maven Central Repository as the repositories Gradle should use to look for its 12 | * dependencies. 13 | */ 14 | 15 | repositories { 16 | gradlePluginPortal() 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | dependencyResolutionManagement { 23 | /** 24 | * The dependencyResolutionManagement {repositories {...}} 25 | * block is where you configure the repositories and dependencies used by 26 | * all modules in your project, such as libraries that you are using to 27 | * create your application. However, you should configure module-specific 28 | * dependencies in each module-level build.gradle file. For new projects, 29 | * Android Studio includes Google's Maven repository and the Maven Central 30 | * Repository by default, but it does not configure any dependencies (unless 31 | * you select a template that requires some). 32 | */ 33 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) 34 | 35 | repositories { 36 | google() 37 | mavenCentral() 38 | } 39 | } 40 | 41 | rootProject.name = "Rust Android Sample" 42 | include(":app") 43 | -------------------------------------------------------------------------------- /desktop-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Rust Everywhere: Desktop Sample 2 | 3 | - TODO: PRs are more than welcome ;) 4 | -------------------------------------------------------------------------------- /ios-sample/.gitignore: -------------------------------------------------------------------------------- 1 | ### Swift ### 2 | # Xcode 3 | # 4 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 5 | 6 | ## User settings 7 | xcuserdata/ 8 | 9 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 10 | *.xcscmblueprint 11 | *.xccheckout 12 | 13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 14 | build/ 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | 29 | ## App packaging 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 45 | # hence it is not needed unless you have added a package configuration file to your project 46 | # .swiftpm 47 | 48 | .build/ 49 | 50 | # CocoaPods 51 | # We recommend against adding the Pods directory to your .gitignore. However 52 | # you should judge for yourself, the pros and cons are mentioned at: 53 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 54 | # Pods/ 55 | # Add this line if you want to avoid checking in source code from the Xcode workspace 56 | # *.xcworkspace 57 | 58 | # Carthage 59 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 60 | # Carthage/Checkouts 61 | 62 | Carthage/Build/ 63 | 64 | # Accio dependency management 65 | Dependencies/ 66 | .accio/ 67 | 68 | # fastlane 69 | # It is recommended to not store the screenshots in the git repo. 70 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 71 | # For more information about the recommended setup visit: 72 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 73 | 74 | fastlane/report.xml 75 | fastlane/Preview.html 76 | fastlane/screenshots/**/*.png 77 | fastlane/test_output 78 | 79 | # Code Injection 80 | # After new code Injection tools there's a generated folder /iOSInjectionProject 81 | # https://github.com/johnno1962/injectionforxcode 82 | 83 | iOSInjectionProject/ 84 | -------------------------------------------------------------------------------- /ios-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Rust Everywhere: iOS Sample 2 | 3 | - TODO: PRs are more than welcome ;) 4 | -------------------------------------------------------------------------------- /rust-library/.gitignore: -------------------------------------------------------------------------------- 1 | ### Rust ### 2 | # Generated by Cargo 3 | # will have compiled files and executables 4 | /target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # Cargo local configuration 11 | .cargo 12 | -------------------------------------------------------------------------------- /rust-library/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#3399ff", 4 | "activityBar.background": "#3399ff", 5 | "activityBar.foreground": "#15202b", 6 | "activityBar.inactiveForeground": "#15202b99", 7 | "activityBarBadge.background": "#bf0060", 8 | "activityBarBadge.foreground": "#e7e7e7", 9 | "commandCenter.border": "#e7e7e799", 10 | "sash.hoverBorder": "#3399ff", 11 | "statusBar.background": "#007fff", 12 | "statusBar.foreground": "#e7e7e7", 13 | "statusBarItem.hoverBackground": "#3399ff", 14 | "statusBarItem.remoteBackground": "#007fff", 15 | "statusBarItem.remoteForeground": "#e7e7e7", 16 | "titleBar.activeBackground": "#007fff", 17 | "titleBar.activeForeground": "#e7e7e7", 18 | "titleBar.inactiveBackground": "#007fff99", 19 | "titleBar.inactiveForeground": "#e7e7e799" 20 | }, 21 | "peacock.color": "#007fff" 22 | } -------------------------------------------------------------------------------- /rust-library/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "cryptor", 4 | "cryptor_jni", 5 | "cryptor_global" 6 | ] 7 | 8 | [profile.release] 9 | panic = 'abort' -------------------------------------------------------------------------------- /rust-library/README.md: -------------------------------------------------------------------------------- 1 | ## Rust Crypto Library (Encryption/Decryption) 2 | 3 | **Crypto** is a SAMPLE **Rust Crate** that showcases **cross-platform compilation for different projects and environments**. In terms of functinality and for **LEARNING PURPOSE**, it simulates **'encryption/decryption'** by using `base64 encoding/decoding`. 4 | 5 | In order to **fully understand the purpose of this repo**, please refer to the follwing blog posts: 6 | 7 | - [Rust cross-platform... The Android part...](https://fernandocejas.com/blog/engineering/2023-07-27-rust-cross-platform-android/). 8 | - **TODO:** Blog Post two 9 | - **TODO:** Blog Post three 10 | 11 | ## Local Development 12 | 13 | - `cargo build` -> builds the entire project. 14 | - `cargo test` -> run all the tests. 15 | 16 | ## Sub-projects 17 | 18 | The Crypto Library is composed by a [Rust Workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) containing a [set of crates](Cargo.toml). 19 | 20 |

21 | rust-cross-platform-crypto-project-overview 22 |

23 | 24 | ### **cryptor** 25 | 26 | It is the **core domain library**, which contains the main logic for **encryption/decryption.** 27 | 28 | #### Available commands 29 | 30 | ```bash 31 | $ cargo build // build the debug version of the project. 32 | $ cargo build --release // build the release version of the project. 33 | $ cargo test // run all the tests. 34 | ``` 35 | ### **cryptor_jni** 36 | 37 | This crate fully depends on the `crypto` crate and its main purpose is to **act as a proxy between Rust and Android (Java/Kotlin) via JNI**. 38 | 39 | #### Project Configuration 40 | 41 | 1. Install the [Android SDK](https://developer.android.com/studio) and [Android NDK](https://developer.android.com/ndk/). 42 | 2. Make sure your `$ANDROID_HOME` is pointing to your SDK location. Mine: `/home/fernando/Android/Sdk`. 43 | 3. Check that your `Android NDK` version matches the one inside the [jni_crypto build.rs file](https://github.com/android10/Rust-Cross-Platform-Development/blob/main/rust-library/cryptor_jni/build.rs). 44 | - In my case `$ANDROID_HOME/ndk/25.2.9519653` matches with `ANDROID_NDK_VERSION = "25.2.9519653"` inside `build.rs` file. 45 | 46 | #### Available commands 47 | 48 | ```bash 49 | $ cargo build // build the debug version of the project. 50 | $ cargo run --bin release // build the release version of the project for all android targets. 51 | $ cargo run --bin publish // copy all the released libraries/crates inside the android project. 52 | $ cargo test // run all the tests. 53 | ``` 54 | 55 | ### **cryptor_c** 56 | 57 | - Still a **TODO** 58 | 59 | ### **cryptor_wasm** 60 | 61 | - Still a **TODO** 62 | 63 | ## Rust Useful References 64 | 65 | - [Transition a project to a new Rust Edition](https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-project-to-a-new-edition.html) 66 | 67 | ![https://fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 68 | 69 | Buy Me A Coffee 70 | -------------------------------------------------------------------------------- /rust-library/cryptor/.gitignore: -------------------------------------------------------------------------------- 1 | ### Rust ### 2 | # Generated by Cargo 3 | # will have compiled files and executables 4 | /target/ 5 | target/ 6 | 7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 9 | Cargo.lock 10 | -------------------------------------------------------------------------------- /rust-library/cryptor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cryptor" 3 | version = "0.1.0" 4 | authors = ["Fernando Cejas "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at 8 | # https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | # Static Library. 11 | # See: https://doc.rust-lang.org/reference/linkage.html 12 | # See: https://doc.rust-lang.org/cargo/reference/cargo-targets.html 13 | [lib] 14 | crate-type = ["rlib"] 15 | 16 | [dependencies] 17 | base64 = "0.21.0" -------------------------------------------------------------------------------- /rust-library/cryptor/src/lib.rs: -------------------------------------------------------------------------------- 1 | use base64::{ 2 | Engine as _, 3 | engine::general_purpose::STANDARD as base64Engine 4 | }; 5 | 6 | /// Encrypts a String. 7 | /// 8 | /// Example: 9 | /// ``` 10 | /// use cryptor::encrypt; 11 | /// assert_eq!(encrypt("hello"), "aGVsbG8="); 12 | /// assert_eq!(encrypt(""), ""); 13 | /// ``` 14 | pub fn encrypt(to: &str) -> String { 15 | base64Engine.encode(String::from(to)) 16 | } 17 | 18 | /// Decrypts a String. 19 | /// 20 | /// Example: 21 | /// ``` 22 | /// use cryptor::decrypt; 23 | /// assert_eq!(decrypt("aGVsbG8="), "hello"); 24 | /// assert_eq!(decrypt(""), ""); 25 | /// ``` 26 | pub fn decrypt(from: &str) -> String { 27 | let base64_bytes = base64Engine.decode( 28 | String::from(from) 29 | ).unwrap_or(vec![]); 30 | 31 | match String::from_utf8(base64_bytes) { 32 | Ok(result) => result, 33 | Err(_) => "".to_owned() 34 | } 35 | } -------------------------------------------------------------------------------- /rust-library/cryptor/tests/integration_tests.rs: -------------------------------------------------------------------------------- 1 | use cryptor; 2 | 3 | #[test] 4 | fn test_encrypt_string() { 5 | let to_encrypt = "hello_world_from_rust"; 6 | let str_encoded_b64 = "aGVsbG9fd29ybGRfZnJvbV9ydXN0"; 7 | 8 | let encrypted_result = cryptor::encrypt(&to_encrypt); 9 | 10 | assert_eq!(str_encoded_b64, encrypted_result); 11 | } 12 | 13 | #[test] 14 | fn test_decrypt_string() { 15 | let str_encoded_b64 = "aGVsbG9fd29ybGRfZnJvbV9ydXN0"; 16 | let str_decoded_b64 = "hello_world_from_rust"; 17 | 18 | let decrypted_result = cryptor::decrypt(&str_encoded_b64); 19 | 20 | assert_eq!(str_decoded_b64, decrypted_result); 21 | } 22 | 23 | #[test] 24 | fn test_decrypt_empty_string() { 25 | let empty_str = ""; 26 | 27 | let decrypted_result: String = cryptor::decrypt(&empty_str); 28 | 29 | assert_eq!(empty_str, decrypted_result) 30 | } 31 | 32 | #[test] 33 | fn test_decrypt_invalid_base64_string() { 34 | let invalid_base64_str = "dfoiuerw892"; 35 | 36 | let decrypted_result: String = cryptor::decrypt(&invalid_base64_str); 37 | 38 | assert_eq!("", decrypted_result) 39 | } -------------------------------------------------------------------------------- /rust-library/cryptor_c/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cryptor_c" 3 | version = "0.1.0" 4 | authors = ["Fernando Cejas "] 5 | edition = "2021" 6 | 7 | # See more keys and their definitions at 8 | # https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | # Dynamic Library. 11 | # See: https://doc.rust-lang.org/reference/linkage.html 12 | # See: https://doc.rust-lang.org/cargo/reference/cargo-targets.html 13 | [lib] 14 | crate-type = ["dylib"] 15 | 16 | [dependencies] 17 | cryptor = { path = "../cryptor", version = "0.1.0" } 18 | -------------------------------------------------------------------------------- /rust-library/cryptor_c/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{CStr, CString}; 2 | use std::os::raw::c_char; 3 | 4 | /// Encrypts a String. 5 | #[no_mangle] 6 | pub extern "C" fn encrypt(to: *const c_char) -> *mut c_char { 7 | let to = unsafe { CStr::from_ptr(to).to_str().unwrap() }; 8 | let result = cryptor::encrypt(to); 9 | 10 | CString::new(result).unwrap().into_raw() 11 | } 12 | 13 | /// Decrypts a String. 14 | #[no_mangle] 15 | pub extern "C" fn decrypt(from: *const c_char) -> *mut c_char { 16 | let from = unsafe { CStr::from_ptr(from).to_str().unwrap() }; 17 | let result = cryptor::decrypt(from); 18 | 19 | CString::new(result).unwrap().into_raw() 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | 26 | #[test] 27 | fn test_encrypt_string() { 28 | let str_encoded_b64 = "aGVsbG9fd29ybGRfZnJvbV9j"; 29 | let to_encrypt = "hello_world_from_c"; 30 | let to_encrypt_cstring = CString::new(to_encrypt).unwrap(); 31 | 32 | let encrypted_result = encrypt(to_encrypt_cstring.as_ptr()); 33 | let encrypted_result = unsafe { CStr::from_ptr(encrypted_result).to_string_lossy().into_owned() }; 34 | 35 | assert_eq!(encrypted_result, str_encoded_b64); 36 | } 37 | 38 | #[test] 39 | fn test_decrypt_string() { 40 | let str_decoded_b64 = "hello_world_from_c"; 41 | let to_decrypt_b64 = "aGVsbG9fd29ybGRfZnJvbV9j"; 42 | let to_decrypt_b64_cstring = CString::new(to_decrypt_b64).unwrap(); 43 | 44 | let decrypted_result = decrypt(to_decrypt_b64_cstring.as_ptr()); 45 | let decrypted_result = unsafe { CStr::from_ptr(decrypted_result).to_string_lossy().into_owned() }; 46 | 47 | assert_eq!(decrypted_result, str_decoded_b64); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rust-library/cryptor_global/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cryptor_global" 3 | version = "0.1.0" 4 | authors = ["Fernando Cejas "] 5 | edition = "2021" 6 | 7 | [lib] 8 | crate-type = ["rlib"] 9 | 10 | [dependencies] 11 | -------------------------------------------------------------------------------- /rust-library/cryptor_global/src/console.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | use std::io::{ 3 | self, 4 | Write, 5 | }; 6 | 7 | 8 | /// Runs a command line command. 9 | /// 10 | /// ## Example: 11 | /// ``` 12 | /// use cryptor_global::console::run_command; 13 | /// 14 | /// let mut command_args = Vec::new(); 15 | /// command_args.push("ls"); 16 | /// command_args.push("a"); 17 | /// 18 | /// run_command("ls", &command_args.as_slice()); 19 | /// ``` 20 | pub fn run_command(comand: &str, args: &[&str]) { 21 | let mut command_with_args = Command::new(comand); 22 | 23 | for arg in args.iter() { 24 | command_with_args.arg(arg); 25 | }; 26 | 27 | let output = command_with_args.output().expect("Failed to execute command"); 28 | 29 | io::stdout().write_all(&output.stdout).unwrap(); 30 | io::stderr().write_all(&output.stderr).unwrap(); 31 | } 32 | 33 | /// Prints a message to the standard output. 34 | /// 35 | /// Example: 36 | /// ``` 37 | /// use cryptor_global::console; 38 | /// console::out("hello"); 39 | /// ``` 40 | pub fn out(message: &str) { 41 | println!("Message: {}", &message); 42 | } 43 | 44 | /// Prints a message to the standard output. 45 | /// 46 | /// Example: 47 | /// ``` 48 | /// use cryptor_global::console; 49 | /// console::out("hello"); 50 | /// ``` 51 | pub fn print(message: String) { 52 | println!("Message: {}", &message); 53 | } -------------------------------------------------------------------------------- /rust-library/cryptor_global/src/io.rs: -------------------------------------------------------------------------------- 1 | static CARGO_CONFIG_DIR_NAME: &str = ".cargo"; 2 | static CARGO_CONFIG_FILE_NAME: &str = "config"; 3 | 4 | 5 | use std::fs; 6 | use std::path::PathBuf; 7 | use std::fs::File; 8 | use std::io::Result; 9 | use std::io::ErrorKind; 10 | 11 | /// 12 | /// Creates a cargo config file in the in the directory 13 | /// passed as a parameter. 14 | /// 15 | /// Example: 16 | /// ``` 17 | /// use std::env; 18 | /// use cryptor_global::io; 19 | /// let mut config_file = io::create_cargo_config_file(&env::current_dir().unwrap()); 20 | /// ``` 21 | pub fn create_cargo_config_file(dir_path: &PathBuf) -> File { 22 | let config_dir_path = dir_path.join(CARGO_CONFIG_DIR_NAME); 23 | create_config_dir(&config_dir_path).unwrap_or_else(|error| { 24 | if error.kind() != ErrorKind::AlreadyExists { 25 | panic!("Could not create cargo configuration directory: {:?}", error); 26 | } 27 | }); 28 | 29 | let config_file_path = config_dir_path.join(CARGO_CONFIG_FILE_NAME); 30 | create_config_file(&config_file_path).expect("Could not create cargo configuration file.") 31 | } 32 | 33 | fn create_config_dir(dir_path: &PathBuf) -> Result<()> { 34 | fs::create_dir(&dir_path) 35 | } 36 | 37 | fn create_config_file(file_path: &PathBuf) -> Result { 38 | File::create(&file_path) 39 | } 40 | 41 | /// 42 | /// Copies the contents of one file to another. 43 | /// 44 | /// - https://doc.rust-lang.org/std/fs/fn.copy.html 45 | /// 46 | pub fn copy_file(from: &str, to: &str)-> std::io::Result<()> { 47 | fs::copy(from, to)?; 48 | Ok(()) 49 | } -------------------------------------------------------------------------------- /rust-library/cryptor_global/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod io; 2 | pub mod console; 3 | pub mod system; -------------------------------------------------------------------------------- /rust-library/cryptor_global/src/system.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | /// 4 | /// Returns whehter the current build is Release. 5 | /// 6 | pub fn is_release() -> bool { 7 | Ok("release".to_owned()) == env::var("PROFILE") 8 | } 9 | 10 | /// 11 | /// Tells Cargo that if the given file changes, 12 | /// to rerun the build script file passed as a 13 | /// parameter. 14 | /// 15 | /// We communicate with cargo from within 16 | /// the script by writing to stdout. 17 | /// 18 | /// Example: 19 | /// ``` 20 | /// use cryptor_global::system::rerun_if_changed; 21 | /// rerun_if_changed("build.rs"); 22 | /// ``` 23 | pub fn rerun_if_changed(file_name: &str) { 24 | println!("cargo:rerun-if-changed={}", file_name); 25 | } 26 | 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn test_given_debug_profile_then_release_returns_false() { 34 | assert_eq!( 35 | is_release(), false, 36 | "'is_release()' fn is not returning the right value'", 37 | ); 38 | } 39 | } -------------------------------------------------------------------------------- /rust-library/cryptor_jni/.gitignore: -------------------------------------------------------------------------------- 1 | ### Rust ### 2 | # Generated by Cargo 3 | # will have compiled files and executables 4 | /target/ 5 | target/ 6 | 7 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 8 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 9 | Cargo.lock 10 | -------------------------------------------------------------------------------- /rust-library/cryptor_jni/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cryptor_jni" 3 | version = "0.1.0" 4 | authors = ["Fernando Cejas "] 5 | edition = "2021" 6 | build = "build.rs" 7 | 8 | # See more keys and their definitions at 9 | # https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [target.'cfg(target_os="android")'.dependencies] 12 | jni = { version = "0.21.1", default-features = false } 13 | 14 | # Dynamic Library: https://doc.rust-lang.org/reference/linkage.html 15 | [lib] 16 | crate-type = ["staticlib", "cdylib"] 17 | 18 | [dependencies] 19 | phf = { version = "0.11.1", features = ['macros'] } 20 | serde = { version = '1.0.118', features = ['derive'] } 21 | toml = "0.7.2" 22 | cryptor = { path = "../cryptor", version = "0.1.0" } 23 | cryptor_global = { path = "../cryptor_global", version = "0.1.0" } 24 | 25 | [build-dependencies] 26 | phf = { version = "0.11.1", features = ['macros'] } 27 | serde = { version = '1.0.118', features = ['derive'] } 28 | toml = "0.7.2" 29 | cryptor_global = { path = "../cryptor_global", version = "0.1.0" } -------------------------------------------------------------------------------- /rust-library/cryptor_jni/build.rs: -------------------------------------------------------------------------------- 1 | // @See Build Scripts: 2 | // - https://doc.rust-lang.org/cargo/reference/build-scripts.html 3 | // - https://doc.rust-lang.org/cargo/reference/build-script-examples.html 4 | // - https://rust-lang.github.io/rust-bindgen/tutorial-3.html 5 | 6 | // Avoid false positive warning due to 7 | // calling members from another module. 8 | #![allow(dead_code)] 9 | 10 | use std::env; 11 | use std::collections::HashMap; 12 | use std::io::Write; 13 | 14 | use phf::phf_map; 15 | 16 | use serde::Serialize; 17 | use toml; 18 | 19 | use std::path::MAIN_SEPARATOR_STR; 20 | 21 | use cryptor_global::io; 22 | use cryptor_global::console; 23 | use cryptor_global::system; 24 | 25 | 26 | // ----------------------------------------------------------------------------------------------- 27 | // C O N F I G U R A T I O N 28 | // ----------------------------------------------------------------------------------------------- 29 | // Cargo Config: 30 | // - https://doc.rust-lang.org/cargo/reference/config.html 31 | // 32 | // Andrid NDK Configuration: 33 | // - https://developer.android.com/studio/projects/install-ndk#specific-version 34 | // 35 | // Android Use the NDK with other build systems: 36 | // - https://developer.android.com/ndk/guides/other_build_systems 37 | // ----------------------------------------------------------------------------------------------- 38 | static ANDROID_NDK_VERSION: &str = "25.2.9519653"; 39 | 40 | /// 41 | /// Due to Rust limitations on generating a static Map with a custom type, a tuple is 42 | /// needed with the following value representation: 43 | /// 44 | /// - Tuple.0 = Archiver to be used to assemble static libraries compiled from C/C++ (Rust) code. 45 | /// - Tuple.1 = Linker to be used to link Rust code. 46 | /// - Tuple.2 = ABI (Application Binary Interface) related to Tuple.0 target. 47 | /// 48 | /// ABI (Application Binary Interface) explanation: 49 | /// 50 | /// Each generated Target relates to an ABI (Application Binary Interface, which is a combination of 51 | /// CPU type and instruction set). According to the official android documentation, we map each 52 | /// target with its corresponding directory (ABI) in our Android client as following: 53 | /// 54 | /// ``` 55 | /// ------------------------------------------------------------------------------------- 56 | /// ANDROID TARGET ABI (folder in the android project inside `jniLibs`) 57 | /// ------------------------------------------------------------------------------------ 58 | /// armv7a-linux-androideabi ---> armeabi-v7a 59 | /// aarch64-linux-android ---> arm64-v8a 60 | /// i686-linux-android ---> x86 61 | /// x86_64-linux-android ---> x86_64 62 | /// ------------------------------------------------------------------------------------- 63 | /// ``` 64 | /// 65 | /// For more information, check the Official Android documentation: 66 | /// - https://developer.android.com/ndk/guides/other_build_systems 67 | /// - https://developer.android.com/ndk/guides/abis 68 | /// 69 | /// And the Rust Cross Compilation documentation: 70 | /// - https://rust-lang.github.io/rustup/cross-compilation.html 71 | /// 72 | pub static ANDROID_TARGET_ABI_CONFIG: phf::Map<&'static str, (&'static str, &'static str, &'static str)> = phf_map! { 73 | "armv7-linux-androideabi" => ("arm-linux-androideabi-ar", "armv7a-linux-androideabi21-clang", "armeabi-v7a"), 74 | "aarch64-linux-android" => ("aarch64-linux-android-ar", "aarch64-linux-android21-clang", "arm64-v8a"), 75 | "i686-linux-android" => ("i686-linux-android-ar", "i686-linux-android21-clang", "x86"), 76 | "x86_64-linux-android" => ("x86_64-linux-android-ar", "x86_64-linux-android21-clang", "x86_64"), 77 | }; 78 | 79 | /// 80 | /// This returns the android tool chain path 81 | /// based on current host operating system. 82 | /// 83 | /// NDK tag according to the host OS: 84 | /// 85 | /// ``` 86 | /// ----------------------------------------- 87 | /// NDK OS Variant Host Tag 88 | /// ---------------------------------------- 89 | /// Linux ---> linux-x86_64 90 | /// macOS ---> darwin-x86_64 91 | /// 64-bit Windows ---> windows-x86_64 92 | /// ----------------------------------------- 93 | /// ``` 94 | /// 95 | /// For more information, check the Official Android documentation: 96 | /// - https://developer.android.com/ndk/guides/other_build_systems 97 | /// 98 | /// ## Examples 99 | /// 100 | /// `/toolchains/llvm/prebuilt/linux-x86_64/bin/` 101 | /// 102 | fn android_tool_chain_path() -> String { 103 | // https://doc.rust-lang.org/std/env/consts/constant.OS.html 104 | let android_ndk_host_tag = match env::consts::OS { 105 | "linux" => "linux-x86_64", 106 | "macos" => "darwin-x86_64", 107 | "windows" => "windows-x86_64", 108 | _ => "linux-x86_64", 109 | }; 110 | 111 | let mut android_tool_chain = String::from(MAIN_SEPARATOR_STR); 112 | 113 | android_tool_chain.push_str("toolchains"); 114 | android_tool_chain.push_str(MAIN_SEPARATOR_STR); 115 | android_tool_chain.push_str("llvm"); 116 | android_tool_chain.push_str(MAIN_SEPARATOR_STR); 117 | android_tool_chain.push_str("prebuilt"); 118 | android_tool_chain.push_str(MAIN_SEPARATOR_STR); 119 | android_tool_chain.push_str(&android_ndk_host_tag); 120 | android_tool_chain.push_str(MAIN_SEPARATOR_STR); 121 | android_tool_chain.push_str("bin"); 122 | android_tool_chain.push_str(MAIN_SEPARATOR_STR); 123 | 124 | android_tool_chain 125 | } 126 | // ----------------------------------------------------------------------------------------------- 127 | 128 | struct AndroidConfig; 129 | impl AndroidConfig { 130 | fn ndk_dir() -> String { 131 | format!( 132 | "{android_sdk_dir}{separator}ndk{separator}{android_ndk_version}", 133 | android_sdk_dir = env::var("ANDROID_HOME").unwrap(), 134 | separator = MAIN_SEPARATOR_STR, 135 | android_ndk_version = ANDROID_NDK_VERSION 136 | ) 137 | } 138 | 139 | fn toolchains_dir() -> String { 140 | format!( 141 | "{ndk}{toolchains}", 142 | ndk = Self::ndk_dir(), 143 | toolchains = android_tool_chain_path(), 144 | ) 145 | } 146 | } 147 | 148 | #[derive(Serialize)] 149 | struct AndroidTargets<'a> { 150 | #[serde(rename(serialize = "target"))] 151 | targets: HashMap<&'a str, AndroidTargetConfig>, 152 | } 153 | 154 | #[derive(Serialize)] 155 | struct AndroidTargetConfig { 156 | // Archiver to be used to assemble static 157 | // libraries compiled from C/C++ (Rust) code. 158 | ar: String, 159 | 160 | //Linker to be used to link Rust code. 161 | linker: String, 162 | } 163 | 164 | fn build_archiver(archiver_path: &str) -> String { 165 | format!( 166 | "{toolchain}{ar}", 167 | toolchain=AndroidConfig::toolchains_dir(), 168 | ar=archiver_path 169 | ) 170 | } 171 | 172 | fn build_linker(linker_path: &str) -> String { 173 | format!( 174 | "{toolchain}{linker}", 175 | toolchain=AndroidConfig::toolchains_dir(), 176 | linker=linker_path 177 | ) 178 | } 179 | 180 | fn android_targets<'a>() -> AndroidTargets<'a> { 181 | let mut android_targets = AndroidTargets { 182 | targets: HashMap::with_capacity(ANDROID_TARGET_ABI_CONFIG.len()) 183 | }; 184 | 185 | for (target, config) in ANDROID_TARGET_ABI_CONFIG.entries() { 186 | let target_config = AndroidTargetConfig { 187 | ar: build_archiver(config.0), 188 | linker: build_linker(config.1) 189 | }; 190 | 191 | android_targets.targets.insert(target, target_config); 192 | } 193 | 194 | AndroidTargets { targets: android_targets.targets } 195 | } 196 | 197 | /// 198 | /// The file `.cargo/config` is necessary to be able to allow 199 | /// `cargo` to create our android targets. 200 | /// 201 | /// - https://doc.rust-lang.org/cargo/reference/config.html 202 | /// 203 | /// The config file should look like this, as 204 | /// an example for Linux and Android NDK 25.2.9519653: 205 | /// 206 | /// ``` 207 | /// [target.armv7-linux-androideabi] 208 | /// ar = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/arm-linux-androideabi-ar" 209 | /// linker = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi21-clang" 210 | 211 | /// [target.aarch64-linux-android] 212 | /// ar = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android-ar" 213 | /// linker = "ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" 214 | 215 | /// [target.i686-linux-android] 216 | /// ar = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android-ar" 217 | /// linker = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/i686-linux-android21-clang" 218 | 219 | /// [target.x86_64-linux-android] 220 | /// ar = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android-ar" 221 | /// linker = "$ANDROID_HOME/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/x86_64-linux-android21-clang" 222 | /// ``` 223 | fn create_android_targets_config_file() { 224 | let targets_config = android_targets(); 225 | let mut config_file = io::create_cargo_config_file(&env::current_dir().unwrap()); 226 | let toml = toml::to_string(&targets_config).unwrap(); 227 | 228 | match config_file.write_all(toml.as_bytes()) { 229 | Ok(_) => println!("Successfully wrote Android Configuration File."), 230 | Err(why) => panic!("Couldn't write Android Configuration: {}", why), 231 | }; 232 | } 233 | 234 | /// 235 | /// Install android targets each for each toolchaing using 236 | /// `rustup`, like so: 237 | /// 238 | /// `rustup target add --toolchain ...` 239 | /// 240 | /// Cross-compilation: 241 | /// - https://rust-lang.github.io/rustup/cross-compilation.html 242 | /// 243 | fn add_android_targets_to_toolchain() { 244 | let mut command_args = Vec::new(); 245 | command_args.push("target"); 246 | command_args.push("add"); 247 | 248 | for target in ANDROID_TARGET_ABI_CONFIG.keys() { 249 | command_args.push(target) 250 | } 251 | 252 | console::run_command("rustup", &command_args.as_slice()); 253 | } 254 | 255 | fn main() { 256 | system::rerun_if_changed("build.rs"); 257 | 258 | create_android_targets_config_file(); 259 | add_android_targets_to_toolchain(); 260 | } 261 | 262 | // 263 | // T E S T S 264 | // 265 | #[cfg(test)] 266 | mod tests { 267 | use super::*; 268 | 269 | #[test] 270 | fn android_targets_and_config_same_size() { 271 | let android_targets = android_targets().targets; 272 | assert_eq!(&android_targets.len() , &ANDROID_TARGET_ABI_CONFIG.len()); 273 | } 274 | 275 | #[test] 276 | fn android_targets_links_to_proper_target_config() { 277 | for target_config in ANDROID_TARGET_ABI_CONFIG.entries() { 278 | let target_config_key = target_config.0; 279 | let target_config_abi = target_config.1.2; 280 | 281 | if target_config_key.starts_with("armv7") { assert_eq!(target_config_abi, "armeabi-v7a") } 282 | if target_config_key.starts_with("aarch64") { assert_eq!(target_config_abi, "arm64-v8a") } 283 | if target_config_key.starts_with("i686") { assert_eq!(target_config_abi, "x86") } 284 | if target_config_key.starts_with("x86_64") { assert_eq!(target_config_abi, "x86_64") } 285 | } 286 | } 287 | } -------------------------------------------------------------------------------- /rust-library/cryptor_jni/src/bin/publish.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// This is a binary targets, which is an executable program 3 | /// that can be run after crate compilation. 4 | /// 5 | /// It will basically copy the 'release' version 6 | /// of this crate to the corresponding android 7 | /// project. 8 | /// 9 | /// ## Examples 10 | /// ``` 11 | /// $ cd cryptor_jni/ 12 | /// $ cargo run --bin publish 13 | /// ``` 14 | /// 15 | /// For more information, refer to the official doc: 16 | /// - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries 17 | /// 18 | 19 | 20 | // https://doc.rust-lang.org/reference/items/modules.html 21 | #[path="../../build.rs"] 22 | mod build; 23 | 24 | use std::env; 25 | use std::error::Error; 26 | use std::path::PathBuf; 27 | use std::path::MAIN_SEPARATOR_STR; 28 | 29 | use cryptor_global::{ 30 | console, 31 | io, 32 | }; 33 | 34 | // Represents the crate/lib file name generated 35 | static JNI_LIB_FILE_NAME: &str = "libcryptor_jni.so"; 36 | 37 | /// 38 | /// Returns the project directory path. 39 | /// 40 | /// ## Examples 41 | /// 42 | /// `$ rust-library/` 43 | /// 44 | fn project_dir_path() -> String { 45 | let current_dir_path = env::current_dir().expect( 46 | "Cannot read current directory" 47 | ); 48 | let target_dir_path = current_dir_path.parent().expect( 49 | "Cannot find/read 'rust-library' directory" 50 | ); 51 | 52 | target_dir_path.as_os_str().to_str().expect( 53 | "Cannot validate 'rust-library' directory" 54 | ).to_owned() 55 | } 56 | 57 | /// 58 | /// Returns the jni directory path in the android project 59 | /// where the release version of this crate should be 60 | /// placed. 61 | /// 62 | /// ## Arguments 63 | /// 64 | /// * `android_jni_lib_folder` - A string slice that holds the name of the android target. 65 | /// 66 | /// ## Examples 67 | /// 68 | /// `$ android-sample/app/src/main/jniLibs` 69 | /// 70 | fn android_jni_dir_path(android_jni_lib_folder: &str) -> String { 71 | let project_dir = PathBuf::from(project_dir_path()); 72 | let android_project_dir_path = project_dir.parent().expect( 73 | "Cannot find/read 'android-sample' directory" 74 | ); 75 | 76 | let mut android_jni_file_path = android_project_dir_path.as_os_str().to_str().expect( 77 | "Cannot validate 'android-sample' directory" 78 | ).to_owned(); 79 | 80 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 81 | android_jni_file_path.push_str("android-sample"); 82 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 83 | android_jni_file_path.push_str("app"); 84 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 85 | android_jni_file_path.push_str("src"); 86 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 87 | android_jni_file_path.push_str("main"); 88 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 89 | android_jni_file_path.push_str("jniLibs"); 90 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 91 | android_jni_file_path.push_str(&android_jni_lib_folder); 92 | android_jni_file_path.push_str(MAIN_SEPARATOR_STR); 93 | android_jni_file_path.push_str(JNI_LIB_FILE_NAME); 94 | 95 | android_jni_file_path 96 | } 97 | 98 | /// 99 | /// Returns the file path where the 100 | /// release version of this crate 101 | /// is placed. 102 | /// 103 | /// ## Arguments 104 | /// 105 | /// * `project_dir_path` - A string slice that holds thsi project directory path. 106 | /// * `android_target` - A string slice that holds the name of the android target. 107 | /// 108 | /// ## Examples 109 | /// 110 | /// `$ rust-library/target/x86_64-linux-android/release/JNI_LIB_FILE_NAME` 111 | /// 112 | fn crate_file_path_for_target(project_dir_path: &str, android_target: &str) -> String { 113 | let mut crate_lib_file_path = project_dir_path.to_owned(); 114 | 115 | crate_lib_file_path.push_str(MAIN_SEPARATOR_STR); 116 | crate_lib_file_path.push_str("target"); 117 | crate_lib_file_path.push_str(MAIN_SEPARATOR_STR); 118 | crate_lib_file_path.push_str(&android_target); 119 | crate_lib_file_path.push_str(MAIN_SEPARATOR_STR); 120 | crate_lib_file_path.push_str("release"); 121 | crate_lib_file_path.push_str(MAIN_SEPARATOR_STR); 122 | crate_lib_file_path.push_str(JNI_LIB_FILE_NAME); 123 | 124 | crate_lib_file_path 125 | } 126 | 127 | /// 128 | /// Copy the release version of each android target to the corresponding 129 | /// directory in the android project. 130 | /// 131 | fn publish_jni_lib_to_android_project() -> Result> { 132 | let project_dir_path = project_dir_path(); 133 | 134 | // we loop through all android targets 135 | for android_target in build::ANDROID_TARGET_ABI_CONFIG.keys() { 136 | // get the path of the 'JNI_LIB_FILE_NAME' file. 137 | let crate_lib_file_path = crate_file_path_for_target(&project_dir_path, &android_target); 138 | 139 | // get the jni android folder name to place our 'JNI_LIB_FILE_NAME' file. 140 | let android_jni_lib_folder = build::ANDROID_TARGET_ABI_CONFIG.get(&android_target).expect( 141 | "Cannot find 'jniLib' folder in 'android-sample' project." 142 | ).2; 143 | 144 | // build the entire jniLib based on the current android target 145 | let android_lib_file_path = android_jni_dir_path(&android_jni_lib_folder); 146 | 147 | if PathBuf::from(&crate_lib_file_path).exists() { 148 | io::copy_file(&crate_lib_file_path, &android_lib_file_path)?; 149 | } else { 150 | return Err("Error copying library file".into()) 151 | } 152 | } 153 | 154 | Ok("JNI Libs Succesfully Published to the Android Project!!!".to_owned()) 155 | } 156 | 157 | fn main() { 158 | match publish_jni_lib_to_android_project() { 159 | Ok(success_message) => console::print(success_message), 160 | Err(error) => console::print(error.to_string()), 161 | } 162 | } 163 | 164 | 165 | #[cfg(test)] 166 | mod tests { 167 | use super::*; 168 | 169 | #[test] 170 | fn android_jni_dir_path_includes_proper_folder_names() { 171 | let jni_folder_name = "arm64-v8a"; 172 | let jni_dir = android_jni_dir_path(jni_folder_name); 173 | 174 | assert!(jni_dir.contains("android-sample")); 175 | assert!(jni_dir.contains("app")); 176 | assert!(jni_dir.contains("src")); 177 | assert!(jni_dir.contains("main")); 178 | assert!(jni_dir.contains("jniLibs")); 179 | assert!(jni_dir.contains(jni_folder_name)); 180 | } 181 | 182 | #[test] 183 | fn crate_file_path_for_target_includes_proper_folder_names() { 184 | let project_dir_path = "fernando"; 185 | let android_target = "android"; 186 | let crate_file_path = crate_file_path_for_target(project_dir_path, android_target); 187 | 188 | assert!(crate_file_path.contains(project_dir_path)); 189 | assert!(crate_file_path.contains("target")); 190 | assert!(crate_file_path.contains(android_target)); 191 | assert!(crate_file_path.contains("release")); 192 | } 193 | 194 | #[test] 195 | fn proper_project_dir_path() { 196 | let project_dir_path = &project_dir_path(); 197 | 198 | assert!(project_dir_path.contains("rust-library")); 199 | } 200 | } -------------------------------------------------------------------------------- /rust-library/cryptor_jni/src/bin/release.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// This is a binary targets, which is an executable program 3 | /// that can be run after crate compilation. 4 | /// 5 | /// It will basically build release versions of 6 | /// each android target. 7 | /// 8 | /// ## Examples 9 | /// ``` 10 | /// $ cd cryptor_jni/ 11 | /// $ cargo run --bin release 12 | /// ``` 13 | /// 14 | /// For more information, refer to the official doc: 15 | /// - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries 16 | /// 17 | 18 | 19 | // https://doc.rust-lang.org/reference/items/modules.html 20 | #[path="../../build.rs"] 21 | mod build; 22 | 23 | use cryptor_global::console; 24 | 25 | /// 26 | /// Release android targets from Configuration. 27 | /// Check ['build.rs'] File. 28 | /// 29 | /// ## Example 30 | /// 31 | /// ``` 32 | /// cargo build --target armv7-linux-androideabi --release 33 | /// cargo build --target aarch64-linux-android --release 34 | /// cargo build --target i686-linux-android --release 35 | /// cargo build --target x86_64-linux-android --release 36 | /// ``` 37 | fn release_android_targets() { 38 | for target in build::ANDROID_TARGET_ABI_CONFIG.keys() { 39 | console::print(format!("Building Android Target --> {}", &target)); 40 | 41 | let command_args = build_command_args_for_target(&target); 42 | console::run_command("cargo", &command_args); 43 | } 44 | } 45 | 46 | /// 47 | /// Build `cargo` arguments for building android targets. 48 | /// 49 | /// ## Example 50 | /// 51 | /// ``` 52 | /// cargo build --target armv7-linux-androideabi --release 53 | /// ``` 54 | fn build_command_args_for_target(target: &str) -> Vec<&str> { 55 | let mut command_args = Vec::new(); 56 | 57 | command_args.push("build"); 58 | command_args.push("--target"); 59 | command_args.push(target); 60 | command_args.push("--release"); 61 | 62 | command_args 63 | } 64 | 65 | fn main() { 66 | console::out("Releasing Android Targets...Be patient... :)"); 67 | 68 | release_android_targets(); 69 | } 70 | 71 | // 72 | // T E S T S 73 | // 74 | #[cfg(test)] 75 | mod tests { 76 | use super::*; 77 | 78 | #[test] 79 | fn test_build_android_release_argument() { 80 | let command_args = build_command_args_for_target("armv7-linux-androideabi"); 81 | let expected_result = "build --target armv7-linux-androideabi --release"; 82 | 83 | assert_eq!(command_args.join(" "), expected_result.trim()); 84 | } 85 | 86 | #[test] 87 | fn test_build_android_release_arguments_for_all_targets() { 88 | for target in build::ANDROID_TARGET_ABI_CONFIG.keys() { 89 | let command_args = build_command_args_for_target(&target); 90 | let expected_result = format!("build --target {target} --release", target = &target); 91 | 92 | assert_eq!(command_args.join(" "), expected_result.trim()); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /rust-library/cryptor_jni/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// 2 | /// [cfg(target_os = "android")]: Compiler flag ("cfg") which exposes 3 | /// the JNI interface for targeting Android in this case 4 | /// 5 | /// [allow(non_snake_case)]: Tells the compiler not to warn if 6 | /// we are not using snake_case for a variable or function names. 7 | /// For Android Development we want to be consistent with code style. 8 | /// 9 | /// Some useful links: 10 | /// - https://doc.rust-lang.org/reference/items/external-blocks.html 11 | /// - https://doc.rust-lang.org/reference/abi.html 12 | /// - https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier 13 | /// - https://doc.rust-lang.org/reference/items/external-blocks.html 14 | /// 15 | #[cfg(target_os = "android")] 16 | #[allow(non_snake_case)] 17 | pub mod android { 18 | 19 | extern crate jni; 20 | 21 | // This is the interface to the JVM 22 | // that we'll call the majority of our 23 | // methods on. 24 | // @See https://docs.rs/jni/latest/jni/ 25 | use self::jni::JNIEnv; 26 | 27 | // These objects are what you should use as arguments to your 28 | // native function. They carry extra lifetime information to 29 | // prevent them escaping this context and getting used after 30 | // being GC'd. 31 | use self::jni::objects::{JClass, JString}; 32 | 33 | // This is just a pointer. We'll be returning it from our function. 34 | // We can't return one of the objects with lifetime information 35 | // because the lifetime checker won't let us. 36 | use self::jni::sys::jstring; 37 | 38 | use cryptor::encrypt; 39 | use cryptor::decrypt; 40 | 41 | /// 42 | /// Encrypts a String. 43 | /// 44 | #[no_mangle] // This keeps Rust from "mangling" the name so it is unique (crate). 45 | pub extern "system" fn Java_com_fernandocejas_rust_Cryptor_encrypt<'local>( 46 | mut env: JNIEnv<'local>, 47 | // This is the class that owns our static method. It's not going to be used, 48 | // but still must be present to match the expected signature of a static 49 | // native method. 50 | _class: JClass<'local>, 51 | input: JString<'local>, 52 | ) -> jstring { 53 | 54 | // First, we have to get the string out of Java. Check out the `strings` 55 | // module for more info on how this works. 56 | let to_encrypt: String = env.get_string(&input).expect("Couldn't get java string!").into(); 57 | 58 | // We encrypt our str calling the cryptor library 59 | let encrypted_str = encrypt(&to_encrypt); 60 | 61 | // Here we have to create a new Java string to return. Again, more info 62 | // in the `strings` module. 63 | let output = env.new_string(&encrypted_str).expect("Couldn't create Java String!"); 64 | 65 | // Finally, extract the raw pointer to return. 66 | output.into_raw() 67 | } 68 | 69 | /// 70 | /// Decrypts a String. 71 | /// 72 | #[no_mangle] // This keeps Rust from "mangling" the name so it is unique (crate). 73 | pub extern "system" fn Java_com_fernandocejas_rust_Cryptor_decrypt<'local>( 74 | mut env: JNIEnv<'local>, 75 | // This is the class that owns our static method. It's not going to be used, 76 | // but still must be present to match the expected signature of a static 77 | // native method. 78 | _class: JClass<'local>, 79 | input: JString<'local>, 80 | ) -> jstring { 81 | 82 | // First, we have to get the string out of Java. Check out the `strings` 83 | // module for more info on how this works. 84 | let to_decrypt: String = env.get_string(&input).expect("Couldn't get java string!").into(); 85 | 86 | // We decrypt our str calling the cryptor library 87 | let decrypted_str = decrypt(&to_decrypt.to_owned()); 88 | 89 | // Here we have to create a new Java string to return. Again, more info 90 | // in the `strings` module. 91 | let output = env.new_string(&decrypted_str).expect("Couldn't create Java String!"); 92 | 93 | // Finally, extract the raw pointer to return. 94 | output.into_raw() 95 | } 96 | } -------------------------------------------------------------------------------- /web-sample/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | require('@rushstack/eslint-patch/modern-module-resolution') 3 | 4 | module.exports = { 5 | root: true, 6 | 'extends': [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | '@vue/eslint-config-typescript', 10 | '@vue/eslint-config-prettier/skip-formatting' 11 | ], 12 | overrides: [ 13 | { 14 | files: [ 15 | ], 16 | 'extends': [ 17 | ] 18 | } 19 | ], 20 | parserOptions: { 21 | ecmaVersion: 'latest' 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /web-sample/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | .pnpm-debug.log 9 | lerna-debug.log* 10 | 11 | node_modules 12 | .DS_Store 13 | dist 14 | dist-ssr 15 | dev-dist 16 | coverage 17 | *.local 18 | .npmrc 19 | 20 | /cypress/videos/ 21 | /cypress/screenshots/ 22 | 23 | storybook-static 24 | 25 | # Editor directories and files 26 | .vscode/* 27 | !.vscode/extensions.json 28 | .idea 29 | *.suo 30 | *.ntvs* 31 | *.njsproj 32 | *.sln 33 | *.sw? 34 | -------------------------------------------------------------------------------- /web-sample/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "trailingComma": "none" 8 | } -------------------------------------------------------------------------------- /web-sample/.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 20.8.0 2 | -------------------------------------------------------------------------------- /web-sample/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "Vue.vscode-typescript-vue-plugin", 5 | "dbaeumer.vscode-eslint", 6 | "esbenp.prettier-vscode" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /web-sample/README.md: -------------------------------------------------------------------------------- 1 | ## Rust Cross Platform Development: Wev Sample with Vue.js 2 | 3 | In order to **get started,** please refer to the the following **article/post** I have written: 4 | 5 | - [Rust cross-platform... The Web (Vue.js) part...](https://fernandocejas.com/blog/engineering/2023-10-31-rust-cross-platform-web/). 6 | 7 | ## The Idea 8 | 9 | **A picture worth a thousand words!** Here is a summary of what this project tries to accomplished: 10 | 11 | 14 | 15 | TODO 16 | 17 | And here the **implemantion details:** 18 | 19 | 22 | 23 | TODO 24 | 25 | ## Recommended `nodejs` version 26 | 27 | - If you use [asdf-vm](https://asdf-vm.com/) as **Version Manager**, please check the [.tool-versions](.tool-versions) file. 28 | 29 | ## Recommended IDE Setup 30 | 31 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). 32 | 33 | ## Type Support for `.vue` Imports in TS 34 | 35 | TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types. 36 | 37 | If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps: 38 | 39 | 1. Disable the built-in TypeScript Extension 40 | 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette 41 | 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)` 42 | 2. Reload the VSCode window by running `Developer: Reload Window` from the command palette. 43 | 44 | ## Customize configuration 45 | 46 | See [Vite Configuration Reference](https://vitejs.dev/config/). 47 | 48 | ## Local Development 49 | 50 | ```bash 51 | pnpm install # Install project dependencies 52 | pnpm dev # Compile and Hot-Reload for Development 53 | pnpm build # Type-Check, Compile and Minify for Production 54 | ``` 55 | 56 | ## Testing and Code quality 57 | 58 | It includes, Static Analisys, Lint and Unit, Integration and Functions tests. 59 | 60 | ### Run Tests with [Vitest](https://vitest.dev/) 61 | 62 | ```sh 63 | pnpm test 64 | ``` 65 | 66 | ### Lint with [ESLint](https://eslint.org/) 67 | 68 | ```sh 69 | pnpm lint 70 | ``` 71 | 72 | ## References 73 | 74 | - https://vitejs.dev/guide/ 75 | - https://vitest.dev/guide/ 76 | - https://vuejs.org/guide/ 77 | - https://github.com/vuejs/language-tools 78 | - https://pinia.vuejs.org/ 79 | - https://github.com/vuejs/awesome-vue 80 | 81 | ## License 82 | 83 | Copyright 2023 Fernando Cejas 84 | 85 | Licensed under the Apache License, Version 2.0 (the "License"); 86 | you may not use this file except in compliance with the License. 87 | You may obtain a copy of the License at 88 | 89 | http://www.apache.org/licenses/LICENSE-2.0 90 | 91 | Unless required by applicable law or agreed to in writing, software 92 | distributed under the License is distributed on an "AS IS" BASIS, 93 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 94 | See the License for the specific language governing permissions and 95 | limitations under the License. 96 | 97 | 98 | ![https://fernandocejas.com](https://github.com/android10/Sample-Data/blob/master/android10/android10_logo_big.png) 99 | 100 | Buy Me A Coffee 101 | -------------------------------------------------------------------------------- /web-sample/env.d.ts: -------------------------------------------------------------------------------- 1 | /// -------------------------------------------------------------------------------- /web-sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cryptor 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /web-sample/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cryptor", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "preinstall": "npx only-allow pnpm", 7 | "dev": "vite", 8 | "build": "run-p type-check \"build-only {@}\" --", 9 | "preview": "vite preview", 10 | "test": "vitest", 11 | "build-only": "vite build", 12 | "type-check": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", 13 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", 14 | "format": "prettier --write src/" 15 | }, 16 | "dependencies": { 17 | "pinia": "^2.1.6", 18 | "vue": "^3.3.4", 19 | "vue-router": "^4.2.4" 20 | }, 21 | "devDependencies": { 22 | "@rushstack/eslint-patch": "^1.3.3", 23 | "@tsconfig/node18": "^18.2.2", 24 | "@types/jsdom": "^21.1.3", 25 | "@types/node": "^18.17.17", 26 | "@vitejs/plugin-vue": "^4.3.4", 27 | "@vue/eslint-config-prettier": "^8.0.0", 28 | "@vue/eslint-config-typescript": "^12.0.0", 29 | "@vue/test-utils": "^2.4.1", 30 | "@vue/tsconfig": "^0.4.0", 31 | "eslint": "^8.49.0", 32 | "eslint-plugin-vue": "^9.17.0", 33 | "jsdom": "^22.1.0", 34 | "npm-run-all2": "^6.0.6", 35 | "prettier": "^3.0.3", 36 | "start-server-and-test": "^2.0.0", 37 | "typescript": "~5.2.0", 38 | "vite": "^4.4.9", 39 | "vitest": "^0.34.4", 40 | "vue-tsc": "^1.8.11" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /web-sample/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/web-sample/public/favicon.ico -------------------------------------------------------------------------------- /web-sample/public/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /web-sample/public/img/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-sample/public/img/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-sample/src/main/App.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 22 | 23 | 86 | -------------------------------------------------------------------------------- /web-sample/src/main/core/core.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/web-sample/src/main/core/core.ts -------------------------------------------------------------------------------- /web-sample/src/main/core/home/components/AppHeader.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /web-sample/src/main/core/home/views/AboutView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /web-sample/src/main/core/home/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | -------------------------------------------------------------------------------- /web-sample/src/main/core/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | // import HomeView from '../views/HomeView.vue' 3 | import HomeView from '@/main/core/home/views/HomeView.vue' 4 | 5 | const router = createRouter({ 6 | history: createWebHistory(import.meta.env.BASE_URL), 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'home', 11 | component: HomeView 12 | }, 13 | { 14 | path: '/about', 15 | name: 'about', 16 | // route level code-splitting 17 | // this generates a separate chunk (About.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import('@/main/core/home/views/AboutView.vue') 20 | } 21 | ] 22 | }) 23 | 24 | export default router 25 | -------------------------------------------------------------------------------- /web-sample/src/main/features/decryption/components/Decrypt.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /web-sample/src/main/features/decryption/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /web-sample/src/main/features/decryption/decryption.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/web-sample/src/main/features/decryption/decryption.ts -------------------------------------------------------------------------------- /web-sample/src/main/features/decryption/views/DecryptionView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /web-sample/src/main/features/encryption/components/Encrypt.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 42 | -------------------------------------------------------------------------------- /web-sample/src/main/features/encryption/components/icons/IconTooling.vue: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /web-sample/src/main/features/encryption/encryption.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/web-sample/src/main/features/encryption/encryption.ts -------------------------------------------------------------------------------- /web-sample/src/main/features/encryption/views/EncryptionView.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /web-sample/src/main/features/feature.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/android10/Rust-Cross-Platform-Development/8e9a6e636b1c292c7e855eccfc5b9070f1723fc9/web-sample/src/main/features/feature.ts -------------------------------------------------------------------------------- /web-sample/src/main/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import { createPinia } from 'pinia' 3 | 4 | import App from '@/main/App.vue' 5 | import router from '@/main/core/router' 6 | 7 | const app = createApp(App) 8 | 9 | app.use(createPinia()) 10 | app.use(router) 11 | 12 | app.mount('#app') 13 | -------------------------------------------------------------------------------- /web-sample/src/test/core/home/components/AppHeader.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'vitest' 2 | 3 | import { mount } from '@vue/test-utils' 4 | // import AppHeader from '@/main ../AppHeader.vue' 5 | import AppHeader from '@/main/core/home/components/AppHeader.vue' 6 | 7 | describe('AppHeader', () => { 8 | it('renders properly', () => { 9 | const wrapper = mount(AppHeader, { props: { msg: 'Hello Vitest' } }) 10 | expect(wrapper.text()).toContain('Hello Vitest') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /web-sample/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "include": ["env.d.ts", "src/**/*", "src/**/*.vue"], 4 | "exclude": ["src/test/*"], 5 | "compilerOptions": { 6 | "strict": true, 7 | "strictNullChecks": true, 8 | "esModuleInterop": true, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "noUnusedLocals": true, 12 | "skipLibCheck": true, 13 | "composite": true, 14 | "baseUrl": ".", 15 | "paths": { 16 | "@/*": ["./src/*"] 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web-sample/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.node.json" 6 | }, 7 | { 8 | "path": "./tsconfig.app.json" 9 | }, 10 | { 11 | "path": "./tsconfig.vitest.json" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /web-sample/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/node18/tsconfig.json", 3 | "include": [ 4 | "vite.config.*", 5 | "vitest.config.*", 6 | "nightwatch.conf.*", 7 | "playwright.config.*" 8 | ], 9 | "compilerOptions": { 10 | "composite": true, 11 | "module": "ESNext", 12 | "moduleResolution": "Bundler", 13 | "types": ["node"] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /web-sample/tsconfig.vitest.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.app.json", 3 | "exclude": [], 4 | "compilerOptions": { 5 | "composite": true, 6 | "lib": [], 7 | "types": ["node", "jsdom"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /web-sample/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | vue(), 10 | ], 11 | resolve: { 12 | alias: { 13 | '@': fileURLToPath(new URL('./src', import.meta.url)) 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /web-sample/vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { mergeConfig, defineConfig, configDefaults } from 'vitest/config' 3 | import viteConfig from './vite.config' 4 | 5 | export default mergeConfig( 6 | viteConfig, 7 | defineConfig({ 8 | test: { 9 | environment: 'jsdom', 10 | exclude: [...configDefaults.exclude, 'e2e/*'], 11 | root: fileURLToPath(new URL('./', import.meta.url)) 12 | } 13 | }) 14 | ) 15 | --------------------------------------------------------------------------------