├── 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 |
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 | 
52 |
53 |
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 |
13 |
14 |
15 | And here the **implemantion details:**
16 |
17 |
18 |
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 | 
50 |
51 |
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 |
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 | 
68 |
69 |
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 | 
99 |
100 |
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 |
7 |
8 |
9 |
10 |