├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── dimens.xml
│ │ │ │ ├── ic_launcher_background.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ ├── ic_launcher_round.png
│ │ │ │ └── ic_launcher_foreground.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ └── layout
│ │ │ │ └── activity_main.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── schuetz
│ │ │ │ └── rustandroidios
│ │ │ │ ├── JniApi.kt
│ │ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── schuetz
│ │ │ └── rustandroidios
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── schuetz
│ │ └── rustandroidios
│ │ └── JniTests.kt
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── img
├── ios1.png
├── logos_.png
└── android1.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── ios_app
├── ios_app
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── 76.png
│ │ │ ├── 120.png
│ │ │ ├── 152.png
│ │ │ ├── 180.png
│ │ │ └── Contents.json
│ ├── ViewController.swift
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ └── AppDelegate.swift
├── ios_app.xcodeproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ │ └── xcschemes
│ │ │ ├── ios_appTests.xcscheme
│ │ │ └── ios_app.xcscheme
│ └── project.pbxproj
├── Rust-Bridging-Header.h
├── build-rust-xcode.sh
├── core
│ └── mobileapp-ios.h
├── ios_appTests
│ ├── Info.plist
│ └── ios_appTests.swift
└── .gitignore
├── .gitignore
├── .github
└── workflows
│ ├── rust.yml
│ └── android.yml
├── src
├── lib.rs
├── ffi_ios.rs
└── ffi_android.rs
├── Cargo.toml
├── gradle.properties
├── gradlew.bat
├── gradlew
├── README.md
└── Cargo.lock
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/img/ios1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/img/ios1.png
--------------------------------------------------------------------------------
/img/logos_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/img/logos_.png
--------------------------------------------------------------------------------
/img/android1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/img/android1.png
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 | 16dp
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivnsch/rust_android_ios/HEAD/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/ios_app/ios_app.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Rust demo
3 | Returned class: %s
4 | Callback called with: %s
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Jan 02 17:55:58 CET 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.iml
3 | .gradle
4 | /local.properties
5 | .DS_Store
6 | /build
7 | /captures
8 | .externalNativeBuild
9 | target/
10 | app/src/main/libs/
11 | app/src/main/java/net/akaame/myapplication/Session.java
12 | app/src/main/java/net/akaame/myapplication/InternalPointerMarker.java
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ios_app/ios_app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios_app/Rust-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Rust-Bridging-Header.h
3 | // ios_app
4 | //
5 | // Created by Ivan Schuetz on 06.08.19.
6 | // Copyright © 2019 com.schuetz. All rights reserved.
7 | //
8 |
9 | #ifndef Rust_Bridging_Header_h
10 | #define Rust_Bridging_Header_h
11 |
12 | #import "mobileapp-ios.h"
13 |
14 | #endif /* Rust_Bridging_Header_h */
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/rust.yml:
--------------------------------------------------------------------------------
1 | name: Rust
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | env:
10 | CARGO_TERM_COLOR: always
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Build
20 | run: cargo build --verbose
21 | - name: Run tests
22 | run: cargo test --verbose
23 |
24 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[cfg(target_os = "ios")]
2 | mod ffi_ios;
3 | #[cfg(target_os = "android")]
4 | mod ffi_android;
5 |
6 | // Core functionality goes here (or any other Rust file).
7 | // This demo is only about FFI, so empty.
8 | // Possible structures:
9 | // - For simple calculations or services: functions.
10 | // - For more complex scenarios: e.g. function that bootstraps a dependency graph,
11 | // stored in a static variable. the FFI/JNI functions call the dependency graph's functions.
12 |
--------------------------------------------------------------------------------
/ios_app/build-rust-xcode.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Ensure that `cargo` is in PATH, using the default location.
4 | . "$HOME/.cargo/env"
5 |
6 | set -x
7 |
8 | # Go to repo's root
9 | cd "${SRCROOT}/../"
10 |
11 | # Build binaries
12 | cargo +ios-arm64-1.46.0 build --target aarch64-apple-ios --release --lib
13 | cargo build --target=x86_64-apple-ios --release
14 |
15 | # Create fat binary
16 | libtool -static -o ./ios_app/core/libcore ./target/aarch64-apple-ios/release/libcore.a ./target/x86_64-apple-ios/release/libcore.a
17 |
--------------------------------------------------------------------------------
/app/src/test/java/com/schuetz/rustandroidios/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.schuetz.rustandroidios;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "rust_android_ios"
3 | version = "0.0.1"
4 | authors = ["Ivan Schuetz "]
5 | edition = "2018"
6 |
7 | [lib]
8 | name = "core"
9 | crate-type = ["cdylib", "staticlib"]
10 |
11 | [dependencies]
12 | log = "0.4.6"
13 | log-panics = "2.0"
14 |
15 | [target.'cfg(target_os="android")'.dependencies]
16 | jni = { version = "0.16", default-features = false }
17 | android_logger = "0.8"
18 |
19 | [target.'cfg(target_os = "ios")'.dependencies]
20 | libc = "0.2"
21 | core-foundation = "0.6.2"
22 |
23 | [build-dependencies]
24 | env_logger = "0.6"
25 |
--------------------------------------------------------------------------------
/ios_app/core/mobileapp-ios.h:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | typedef struct {
9 | const char *string;
10 | int32_t int_;
11 | } ParamStruct;
12 |
13 | typedef struct {
14 | CFStringRef string;
15 | int32_t int_;
16 | } ReturnStruct;
17 |
18 | int32_t add_values(int32_t value1, int32_t value2);
19 |
20 | CFStringRef greet(const char *who);
21 |
22 | void pass_struct(const ParamStruct *object);
23 |
24 | void register_callback(void (*callback)(CFStringRef));
25 |
26 | ReturnStruct return_struct(void);
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/ios_app/ios_appTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/schuetz/rustandroidios/JniApi.kt:
--------------------------------------------------------------------------------
1 | package com.schuetz.rustandroidios
2 |
3 | class JniApi {
4 | init {
5 | try {
6 | System.loadLibrary("core")
7 | } catch (e: UnsatisfiedLinkError) {
8 | throw UnsatisfiedLinkError("Error linking Rust library. Check that the .so file " +
9 | "for the current architecture is in the libs directory. Error: $e")
10 | }
11 | }
12 |
13 | external fun initLogger()
14 |
15 | external fun add(value1: Int, value2: Int): Int
16 | external fun greet(who: String): String
17 |
18 | external fun passObject(dummy: Dummy)
19 | external fun returnObject(): Dummy
20 |
21 | external fun registerCallback(callback: Callback)
22 | }
23 |
24 | data class Dummy(
25 | val stringPar: String,
26 | val intPar: Int
27 | )
28 |
29 | interface Callback {
30 | fun call(string: String)
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ios_app/ios_app/ViewController.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | class ViewController: UIViewController {
4 |
5 | override func viewDidLoad() {
6 | super.viewDidLoad()
7 |
8 | let greetResult = greet("MyName")!.takeRetainedValue() as String
9 | print("greetResult: \(greetResult)")
10 |
11 | let addResult = add_values(1, 2)
12 | print("addResult: \(addResult)")
13 |
14 | var myStruct = ParamStruct(string: NSString(string: "foo").utf8String, int_: 1)
15 | let structPointer = withUnsafeMutablePointer(to: &myStruct) {
16 | UnsafeMutablePointer($0)
17 | }
18 | let passClassResult: Void = pass_struct(structPointer)
19 | print("passClassResult: \(passClassResult)")
20 |
21 | let returnClassResult = return_struct()
22 | print("returnClassResult: \(returnClassResult)")
23 |
24 | register_callback { string in
25 | print("callback called: \(String(describing: string))")
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/evgeniy/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/schuetz/rustandroidios/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.schuetz.rustandroidios
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import com.schuetz.rustandroidios.R.layout.activity_main
6 |
7 | class MainActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | setContentView(activity_main)
12 |
13 | val jniApi = JniApi()
14 |
15 | jniApi.initLogger()
16 |
17 | val greetResult = jniApi.greet("MyName")
18 | println("JNI greetResult: $greetResult")
19 |
20 | val addResult = jniApi.add(1, 2)
21 | println("JNI addResult: $addResult")
22 |
23 | val passClassResult = jniApi.passObject(Dummy("foo", 1))
24 | println("JNI passClassResult: $passClassResult")
25 |
26 | val returnClassResult = jniApi.returnObject()
27 | println("JNI returnClassResult: $returnClassResult")
28 |
29 | val myCallback = object: Callback {
30 | override fun call(string: String) {
31 | println("JNI callback called: $string")
32 | }
33 | }
34 |
35 | jniApi.registerCallback(myCallback)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 | # When configured, Gradle will run in incubating parallel mode.
14 | # This option should only be used with decoupled projects. More details, visit
15 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
16 | # org.gradle.parallel=true
17 | # AndroidX package structure to make it clearer which packages are bundled with the
18 | # Android operating system, and which are packaged with your app's APK
19 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
20 | android.useAndroidX=true
21 | # Automatically convert third-party libraries to use AndroidX
22 | android.enableJetifier=true
23 | # Kotlin code style for this project: "official" or "obsolete":
24 | kotlin.code.style=official
25 |
--------------------------------------------------------------------------------
/.github/workflows/android.yml:
--------------------------------------------------------------------------------
1 | name: Android
2 |
3 | on:
4 | push:
5 | branches: [ master ]
6 | pull_request:
7 | branches: [ master ]
8 |
9 | jobs:
10 | instrumented_tests:
11 | name: Run Instrumented Tests
12 | runs-on: macos-latest
13 |
14 | steps:
15 | - name: Save logcat output
16 | uses: actions/upload-artifact@master
17 | if: failure()
18 | with:
19 | name: logcat
20 | path: artifacts/logcat.log
21 | - name: checkout
22 | uses: actions/checkout@v2
23 | - name: rust toolchain setup
24 | uses: actions-rs/toolchain@v1
25 | with:
26 | toolchain: stable
27 | - name: install cargo ndk
28 | uses: actions-rs/cargo@v1
29 | with:
30 | command: install
31 | args: cargo-ndk
32 | - name: setup build targets
33 | run: rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
34 | - name: instrumented tests
35 | uses: reactivecircus/android-emulator-runner@v2
36 | with:
37 | api-level: 29
38 | script: ./gradlew connectedAndroidTest --stacktrace
39 | - name: Instrumented tests results
40 | uses: actions/upload-artifact@v2
41 | with:
42 | name: instrumented-tests-results
43 | path: app/build/reports/androidTests/connected/index.html
44 |
45 |
--------------------------------------------------------------------------------
/ios_app/ios_appTests/ios_appTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import ios_app
3 |
4 | class ios_appTests: XCTestCase {
5 |
6 | func testGreet() {
7 | let res = greet("Ivan")!.takeRetainedValue() as String
8 | XCTAssertEqual("Hello 👋 Ivan!", res)
9 | }
10 |
11 | func testAdd() {
12 | let res = add_values(1, 2)
13 | XCTAssertEqual(3, res)
14 | }
15 |
16 | func testPassStruct() {
17 | var myStruct = ParamStruct(string: NSString(string: "foo").utf8String, int_: 1)
18 | let structPointer = withUnsafeMutablePointer(to: &myStruct) {
19 | UnsafeMutablePointer($0)
20 | }
21 | pass_struct(structPointer)
22 | // There's no result. Only testing that it doesn't crash.
23 | }
24 |
25 | func testReturnStruct() {
26 | let res = return_struct()
27 |
28 | let unmanagedString: Unmanaged = res.string
29 | let cfStr: CFString = unmanagedString.takeRetainedValue()
30 | let str = cfStr as String
31 |
32 | XCTAssertEqual(str, "my string parameter")
33 | XCTAssertEqual(res.int_, 123)
34 | }
35 |
36 | func testRegistersCallback() {
37 | register_callback { (string: CFString?) in
38 | let cfStr: CFString = string!
39 | let str = cfStr as String
40 | XCTAssertEqual(str, "Hello callback!")
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/schuetz/rustandroidios/JniTests.kt:
--------------------------------------------------------------------------------
1 | package com.schuetz.rustandroidios
2 |
3 | import androidx.test.ext.junit.runners.AndroidJUnit4
4 | import org.junit.Assert.assertEquals
5 | import org.junit.Test
6 | import org.junit.runner.RunWith
7 |
8 | @RunWith(AndroidJUnit4::class)
9 | class JniTests {
10 |
11 | @Test
12 | fun initLogger() {
13 | JniApi().initLogger()
14 | // There's no result. Only testing that it doesn't crash.
15 | }
16 |
17 | @Test
18 | fun greet() {
19 | val res = JniApi().also { initLogger() }.greet("Ivan")
20 | assertEquals("Hello \uD83D\uDC4B Ivan!", res)
21 | }
22 |
23 | @Test
24 | fun add() {
25 | val res = JniApi().also { initLogger() }.add(111, 222)
26 | assertEquals(333, res)
27 | }
28 |
29 | @Test
30 | fun passClass() {
31 | JniApi().also { initLogger() }.passObject(Dummy("sfds", 2))
32 | // There's no result. Only testing that it doesn't crash.
33 | }
34 |
35 | @Test
36 | fun returnClass() {
37 | val res = JniApi().also { initLogger() }.returnObject()
38 | assertEquals(Dummy("my string parameter", 123), res)
39 | }
40 |
41 | @Test
42 | fun registersCallback() {
43 | JniApi().also { initLogger() }.registerCallback(object : Callback {
44 | override fun call(string: String) {
45 | // Testing callbacks left as an exercise. This requires new dependencies and
46 | // it's not relatd with Rust.
47 | println("Callback called with: $string")
48 | }
49 | })
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/ios_app/ios_app/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/ios_app/ios_app/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ios_app/ios_app.xcodeproj/xcshareddata/xcschemes/ios_appTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/ios_app/ios_app/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "filename" : "120.png",
35 | "idiom" : "iphone",
36 | "scale" : "2x",
37 | "size" : "60x60"
38 | },
39 | {
40 | "filename" : "180.png",
41 | "idiom" : "iphone",
42 | "scale" : "3x",
43 | "size" : "60x60"
44 | },
45 | {
46 | "idiom" : "ipad",
47 | "scale" : "1x",
48 | "size" : "20x20"
49 | },
50 | {
51 | "idiom" : "ipad",
52 | "scale" : "2x",
53 | "size" : "20x20"
54 | },
55 | {
56 | "idiom" : "ipad",
57 | "scale" : "1x",
58 | "size" : "29x29"
59 | },
60 | {
61 | "idiom" : "ipad",
62 | "scale" : "2x",
63 | "size" : "29x29"
64 | },
65 | {
66 | "idiom" : "ipad",
67 | "scale" : "1x",
68 | "size" : "40x40"
69 | },
70 | {
71 | "idiom" : "ipad",
72 | "scale" : "2x",
73 | "size" : "40x40"
74 | },
75 | {
76 | "filename" : "76.png",
77 | "idiom" : "ipad",
78 | "scale" : "1x",
79 | "size" : "76x76"
80 | },
81 | {
82 | "filename" : "152.png",
83 | "idiom" : "ipad",
84 | "scale" : "2x",
85 | "size" : "76x76"
86 | },
87 | {
88 | "idiom" : "ipad",
89 | "scale" : "2x",
90 | "size" : "83.5x83.5"
91 | },
92 | {
93 | "idiom" : "ios-marketing",
94 | "scale" : "1x",
95 | "size" : "1024x1024"
96 | }
97 | ],
98 | "info" : {
99 | "author" : "xcode",
100 | "version" : 1
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/ios_app/ios_app/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ios_app
4 | //
5 | // Created by Ivan Schuetz on 06.08.19.
6 | // Copyright © 2019 com.schuetz. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/ios_app/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | #
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 | #
45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
46 | # hence it is not needed unless you have added a package configuration file to your project
47 | # .swiftpm
48 |
49 | .build/
50 |
51 | # CocoaPods
52 | #
53 | # We recommend against adding the Pods directory to your .gitignore. However
54 | # you should judge for yourself, the pros and cons are mentioned at:
55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
56 | #
57 | # Pods/
58 | #
59 | # Add this line if you want to avoid checking in source code from the Xcode workspace
60 | # *.xcworkspace
61 |
62 | # Carthage
63 | #
64 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
65 | # Carthage/Checkouts
66 |
67 | Carthage/Build/
68 |
69 | # Accio dependency management
70 | Dependencies/
71 | .accio/
72 |
73 | # fastlane
74 | #
75 | # It is recommended to not store the screenshots in the git repo.
76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed.
77 | # For more information about the recommended setup visit:
78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
79 |
80 | fastlane/report.xml
81 | fastlane/Preview.html
82 | fastlane/screenshots/**/*.png
83 | fastlane/test_output
84 |
85 | # Code Injection
86 | #
87 | # After new code Injection tools there's a generated folder /iOSInjectionProject
88 | # https://github.com/johnno1962/injectionforxcode
89 |
90 | iOSInjectionProject/
91 |
92 | # Core
93 | core/libcore
94 |
95 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-android-extensions'
4 |
5 | android {
6 | compileSdkVersion 30
7 | buildToolsVersion "30.0.3"
8 | defaultConfig {
9 | applicationId "com.schuetz.rust_android_ios"
10 | minSdkVersion 21
11 | targetSdkVersion 30
12 | versionCode 1
13 | versionName "1.0.1"
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | sourceSets {
18 | main {
19 | jni.srcDirs = []
20 | jniLibs.srcDir 'src/main/libs'
21 | }
22 | }
23 |
24 | buildTypes {
25 | release {
26 | minifyEnabled true
27 | shrinkResources true
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | }
32 |
33 | dependencies {
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 | testImplementation 'androidx.test.ext:junit:1.1.2'
36 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
37 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
38 | implementation 'androidx.appcompat:appcompat:1.2.0'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
41 | }
42 |
43 | def rustBasePath = ".."
44 | def archTriplets = [
45 | 'armeabi-v7a': 'armv7-linux-androideabi',
46 | 'arm64-v8a': 'aarch64-linux-android',
47 | 'x86_64': 'x86_64-linux-android',
48 | 'x86': 'i686-linux-android'
49 | ]
50 |
51 | // TODO: only pass --release if buildType is release
52 | archTriplets.each { arch, target ->
53 |
54 | // Build Rust lib
55 | tasks.create(name: "cargo-build-$arch", type: Exec, description: "Building core for $arch") {
56 | workingDir rustBasePath
57 | executable "cargo"
58 | args = ["ndk", "--platform", "29", "--target", target, "build", "--verbose"]
59 | }
60 |
61 | // Copy Rust lib into this app's libs directory
62 | tasks.create(name: "rust-deploy-$arch", type: Copy, dependsOn: "cargo-build-$arch",
63 | description: "Copy rust libs for ($arch) to libs") {
64 |
65 | from "$rustBasePath/target/$target/debug"
66 | include "*.so"
67 | into "$rustBasePath/app/src/main/libs/$arch"
68 | }
69 |
70 | // Hook up tasks to execute before building java
71 | tasks.withType(JavaCompile) {
72 | compileTask -> compileTask.dependsOn "rust-deploy-$arch"
73 | }
74 | }
75 |
76 | repositories {
77 | mavenCentral()
78 | }
79 |
--------------------------------------------------------------------------------
/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 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
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 Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/ios_app/ios_app/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/ffi_ios.rs:
--------------------------------------------------------------------------------
1 | use core_foundation::{
2 | base::TCFType,
3 | string::{CFString, CFStringRef},
4 | };
5 | use libc::c_char;
6 | use log::*;
7 | use mpsc::Receiver;
8 | use std::{
9 | sync::mpsc::{self, Sender},
10 | thread,
11 | };
12 |
13 | #[no_mangle]
14 | pub unsafe extern "C" fn greet(who: *const c_char) -> CFStringRef {
15 | let str: String = cstring_to_str(&who).into();
16 | to_cf_str(format!("Hello 👋 {}!", str))
17 | }
18 |
19 | #[no_mangle]
20 | pub unsafe extern "C" fn add_values(
21 | value1: i32,
22 | value2: i32,
23 | ) -> i32 {
24 | info!("Passed value1: {}, value2: {}", value1, value2);
25 | value1 + value2
26 | }
27 |
28 | #[no_mangle]
29 | pub unsafe extern "C" fn pass_struct(
30 | object: *const ParamStruct,
31 | ) {
32 | info!("Received struct from iOS: {:?}", object);
33 | }
34 |
35 | #[no_mangle]
36 | pub unsafe extern "C" fn return_struct(
37 | ) -> ReturnStruct {
38 | ReturnStruct { string: to_cf_str("my string parameter".to_owned()), int: 123 }
39 | }
40 |
41 | pub static mut CALLBACK_SENDER: Option> = None;
42 |
43 | #[no_mangle]
44 | pub unsafe extern "C" fn register_callback(
45 | callback: unsafe extern "C" fn(CFStringRef),
46 | ) {
47 | register_callback_internal(Box::new(callback));
48 |
49 | // Let's send a message immediately, to test it
50 | send_to_callback("Hello callback!".to_owned());
51 | }
52 |
53 | // Convert C string to Rust string slice
54 | unsafe fn cstring_to_str<'a>(cstring: &'a *const c_char) -> &str {
55 | if cstring.is_null() {
56 | // Of course in a real project you'd return Result instead
57 | panic!("cstring is null")
58 | }
59 |
60 | let raw = ::std::ffi::CStr::from_ptr(*cstring);
61 | raw.to_str().expect("Couldn't convert c string to slice")
62 | }
63 |
64 | fn to_cf_str(str: String) -> CFStringRef {
65 | let cf_string = CFString::new(&str);
66 | let cf_string_ref = cf_string.as_concrete_TypeRef();
67 | ::std::mem::forget(cf_string);
68 | cf_string_ref
69 | }
70 |
71 | unsafe fn send_to_callback(string: String) {
72 | match &CALLBACK_SENDER {
73 | Some(s) => {
74 | s.send(string).expect("Couldn't send message to callback!");
75 | }
76 | None => {
77 | info!("No callback registered");
78 | }
79 | }
80 | }
81 |
82 | fn register_callback_internal(callback: Box) {
83 | // Make callback implement Send (marker for thread safe, basically) https://doc.rust-lang.org/std/marker/trait.Send.html
84 | let my_callback =
85 | unsafe { std::mem::transmute::, Box>(callback) };
86 |
87 | // Create channel
88 | let (tx, rx): (Sender, Receiver) = mpsc::channel();
89 |
90 | // Save the sender in a static variable, which will be used to push elements to the callback
91 | unsafe {
92 | CALLBACK_SENDER = Some(tx);
93 | }
94 |
95 | // Thread waits for elements pushed to SENDER and calls the callback
96 | thread::spawn(move || {
97 | for string in rx.iter() {
98 | let cf_string = to_cf_str(string);
99 | my_callback.call(cf_string)
100 | }
101 | });
102 | }
103 |
104 | pub trait MyCallback {
105 | fn call(&self, par: CFStringRef);
106 | }
107 |
108 | impl MyCallback for unsafe extern "C" fn(CFStringRef) {
109 | fn call(&self, par: CFStringRef) {
110 | unsafe {
111 | self(par);
112 | }
113 | }
114 | }
115 |
116 | #[repr(C)]
117 | #[derive(Debug)]
118 | pub struct ParamStruct {
119 | string: *const c_char,
120 | int: i32
121 | }
122 | #[repr(C)]
123 | #[derive(Debug)]
124 | pub struct ReturnStruct {
125 | string: CFStringRef,
126 | int: i32
127 | }
128 |
--------------------------------------------------------------------------------
/ios_app/ios_app.xcodeproj/xcshareddata/xcschemes/ios_app.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
63 |
65 |
71 |
72 |
73 |
74 |
80 |
82 |
88 |
89 |
90 |
91 |
93 |
94 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/src/ffi_android.rs:
--------------------------------------------------------------------------------
1 | use mpsc::Receiver;
2 | use std::{
3 | sync::mpsc::{self, Sender},
4 | thread,
5 | };
6 |
7 | use jni::JavaVM;
8 | use jni::JNIEnv;
9 | use jni::objects::{GlobalRef, JClass, JObject, JString, JValue};
10 | use jni::sys::{jint, jobject, jstring};
11 | use log::info;
12 |
13 | #[no_mangle]
14 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_initLogger(
15 | _: JNIEnv,
16 | _: JClass,
17 | ) {
18 | // Important: Logcat doesn't contain stdout / stderr so we need a custom logger.
19 | // An alternative solution to android_logger, is to register a callback
20 | // (Using the same functionality as registerCallback) to send the logs.
21 | // This allows to process the messages arbitrarily in the app.
22 | android_logger::init_once(
23 | android_logger::Config::default()
24 | .with_min_level(log::Level::Debug)
25 | .with_tag("Hello"),
26 | );
27 | // Log panics rather than printing them.
28 | // Without this, Logcat doesn't show panic message.
29 | log_panics::init();
30 | info!("init log system - done");
31 | }
32 |
33 | #[no_mangle]
34 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_greet(
35 | env: JNIEnv,
36 | _: JClass,
37 | who: JString,
38 | ) -> jstring {
39 | let str: String = env.get_string(who)
40 | .expect("Couldn't create rust string").into();
41 |
42 | let output = env.new_string(format!("Hello 👋 {}!", str))
43 | .expect("Couldn't create java string");
44 |
45 | output.into_inner()
46 | }
47 |
48 | #[no_mangle]
49 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_add(
50 | _env: JNIEnv,
51 | _: JClass,
52 | value1: jint,
53 | value2: jint,
54 | ) -> jint {
55 | info!("Passed value1: {}, value2: {}", value1, value2);
56 | value1 + value2
57 | }
58 |
59 | #[no_mangle]
60 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_passObject(
61 | env: JNIEnv,
62 | _: JClass,
63 | object: JObject,
64 | ) {
65 | let my_int_j_value_res = env.get_field(object, "intPar", "I");
66 | let my_int: i32 = my_int_j_value_res.unwrap().i().unwrap();
67 |
68 | let my_str_j_value = env.get_field(object, "stringPar", "Ljava/lang/String;")
69 | .expect("Couldn't get JValue");
70 | let my_str_j_object = my_str_j_value.l();
71 | let my_str_j_string = JString::from(my_str_j_object.unwrap());
72 |
73 | let my_str_java_string = env.get_string(my_str_j_string).unwrap();
74 | let my_str = my_str_java_string.to_str().unwrap();
75 |
76 | info!("Passed: {}, {}", my_int, my_str);
77 | }
78 |
79 | #[no_mangle]
80 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_returnObject(
81 | env: JNIEnv,
82 | _: JClass,
83 | ) -> jobject {
84 | let cls = env.find_class("com/schuetz/rustandroidios/Dummy");
85 |
86 | let my_int_j_value = JValue::from(123);
87 |
88 | let str_parameter_j_string = env.new_string("my string parameter")
89 | .expect("Couldn't create java string!");
90 | let str_parameter_j_value = JValue::from(JObject::from(str_parameter_j_string));
91 |
92 | let obj = env.new_object(
93 | cls.unwrap(),
94 | "(Ljava/lang/String;I)V",
95 | &[str_parameter_j_value, my_int_j_value],
96 | );
97 |
98 | obj.unwrap().into_inner()
99 | }
100 |
101 | pub static mut CALLBACK_SENDER: Option> = None;
102 |
103 | #[no_mangle]
104 | pub unsafe extern "system" fn Java_com_schuetz_rustandroidios_JniApi_registerCallback(
105 | env: JNIEnv,
106 | _: JClass,
107 | callback: jobject,
108 | ) {
109 | let my_callback = MyCallbackImpl {
110 | java_vm: env.get_java_vm().unwrap(),
111 | callback: env.new_global_ref(callback).unwrap(),
112 | };
113 | register_callback_internal(Box::new(my_callback));
114 |
115 | // Let's send a message immediately, to test it
116 | send_to_callback("Hello callback!".to_owned());
117 | }
118 |
119 | unsafe fn send_to_callback(string: String) {
120 | match &CALLBACK_SENDER {
121 | Some(s) => {
122 | s.send(string).expect("Couldn't send message to callback!");
123 | }
124 | None => {
125 | info!("No callback registered");
126 | }
127 | }
128 | }
129 |
130 | fn register_callback_internal(callback: Box) {
131 | // Make callback implement Send (marker for thread safe, basically) https://doc.rust-lang.org/std/marker/trait.Send.html
132 | let my_callback =
133 | unsafe { std::mem::transmute::, Box>(callback) };
134 |
135 | // Create channel
136 | let (tx, rx): (Sender, Receiver) = mpsc::channel();
137 |
138 | // Save the sender in a static variable, which will be used to push elements to the callback
139 | unsafe {
140 | CALLBACK_SENDER = Some(tx);
141 | }
142 |
143 | // Thread waits for elements pushed to SENDER and calls the callback
144 | thread::spawn(move || {
145 | for string in rx.iter() {
146 | my_callback.call(string)
147 | }
148 | });
149 | }
150 |
151 | trait MyCallback {
152 | fn call(&self, par: String);
153 | }
154 |
155 | struct MyCallbackImpl {
156 | // The callback passed from Android is a local reference: only valid during the method call.
157 | // To store it, we need to put it in a global reference.
158 | // See https://developer.android.com/training/articles/perf-jni#local-and-global-references
159 | callback: GlobalRef,
160 |
161 | // We need JNIEnv to call the callback.
162 | // JNIEnv is valid only in the same thread, so we have to store the vm instead, and use it to get
163 | // a JNIEnv for the current thread.
164 | // See https://developer.android.com/training/articles/perf-jni#javavm-and-jnienvb
165 | java_vm: JavaVM,
166 | }
167 |
168 | impl MyCallback for MyCallbackImpl {
169 | fn call(&self, par: String) {
170 | let env = self.java_vm.attach_current_thread().unwrap();
171 |
172 | let str = env.new_string(par)
173 | .expect("Couldn't create java string!");
174 | let str_j_value = JValue::from(JObject::from(str));
175 |
176 | env.call_method(
177 | self.callback.as_obj(),
178 | "call",
179 | "(Ljava/lang/String;)V",
180 | &[str_j_value],
181 | ).expect("Couldn't call callback");
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Rust core for native Android and iOS apps
2 |
3 | 
4 | 
5 | [[TODO](https://github.com/i-schuetz/rust_android_ios/issues/2) iOS badge]
6 |
7 | This is an example that shows how to use a shared Rust core in native Android and iOS apps.
8 |
9 | ⚠️ Looking for maintainers. If you want to help, just open an issue, or email me ivanhp978@gmail.com
10 |
11 | # Why?
12 |
13 | This approach gives us the best of all worlds: we prevent code duplication by using a shared library. Rust, as a highly performant and safe language is a great fit for mobile. We keep a fully native UI experience and uncomplicated access to the latest APIs of the platforms.
14 |
15 | It's also very flexible, allowing to migrate easily between different platforms, including conventional cross-platform frameworks like Flutter or React Native. For example, you can develop your MVP with Rust+React Native or Rust+Flutter, and migrate later to native iOS/Android, without having to rewrite everything. You even can reuse your core for a web-app, using WebAssembly, or desktop app (where again, you can use native or a cross-platform framework like Electron).
16 |
17 | # Project structure
18 |
19 | - Rust: Repo's root.
20 | - iOS app: `ios_app` directory.
21 | - Android app: Repo's root as well. TODO move it to a folder `android_app`, like the iOS app.
22 |
23 | # Possible setups
24 |
25 | There are different ways to integrate Rust:
26 |
27 | ## As source (like in this repo)
28 |
29 | - Simple setup.
30 |
31 | - Rust is built as part of the app's build process.
32 |
33 | - Not ideal if there are team members unfamiliar with Rust.
34 |
35 | ## As binary
36 |
37 | The Rust binary is distributed as an external dependency.
38 |
39 | - Better for teams with different skillsets. Everyone works mainly with their familiar tech stack.
40 |
41 | - Better separation of concerns / modularity.
42 |
43 | - Considerably more complicated to setup than monorepo (has to be done only once though).
44 |
45 | - Rust binaries have to be versioned and released.
46 |
47 | Note: it is possible to overwrite the external dependency with a local copy for local development.
48 |
49 | ## As "normal" library
50 |
51 | Here the external dependency contains the Rust binary and wrapper libraries for Android and iOS respectively (written in Kotlin and Swift), which hide the FFI/JNI, providing a simple and safe interface to the apps. This makes working with this dependency like with regular third parties.
52 |
53 | An example for this and the binary approaches can be found [here](https://github.com/Co-Epi/app-backend-rust). The Android build contains a wrapper library, which is imported in the Android app with [Gradle](https://github.com/Co-Epi/app-android/blob/54cffa441d27d18ba33d7719a34dc9b5c9125262/app/build.gradle#L168). The iOS build is distributed directly as a binary (no wrapper), using [Carthage](https://github.com/Co-Epi/app-ios/blob/develop/Cartfile#L2).
54 |
55 | # Note on concurrency
56 |
57 | While it's possible to use asynchronous code in core, it's recommended to use blocking apis and add concurrency in the apps. This simplifies the FFI/JNI interfaces (see the [CoEpi](https://github.com/Co-Epi/app-backend-rust) example, where the apps add concurrency via RxSwift/RxJava).
58 |
59 | # "Real world" examples
60 |
61 | ### [CoEpi](https://github.com/Co-Epi/app-backend-rust)
62 |
63 | A mobile contact tracing app for epidemics, with [Android](https://github.com/Co-Epi/app-android) and [iOS](https://github.com/Co-Epi/app-ios) frontends.
64 |
65 | ### [Xi editor](https://github.com/xi-editor/xi-editor)
66 |
67 | A text editor with a lot of frontends: MacOS, GTK, Electron and Windows, among others.
68 |
69 | # Other related projects
70 |
71 | ### [WASM-Rust-d3 example](https://github.com/i-schuetz/wasm-rust-d3)
72 |
73 | An example that shows how to display chart data with d3/JS, using a Rust core to fetch it.
74 |
75 | ### [yew-d3-example](https://github.com/i-schuetz/yew-d3-example)
76 |
77 | Similar to the above, but using the [Yew framework](https://github.com/yewstack/yew)
78 |
79 | # Quickstart
80 |
81 | Install [rustup](https://rustup.rs/)
82 |
83 | ## Android specific steps
84 |
85 | - Ensure the [NDK](https://developer.android.com/ndk/guides) is installed.
86 |
87 | - Set the NDK_HOME environment variable with path to the NDK, e.g:
88 |
89 | ```
90 | export $NDK_HOME=$HOME/Library/Android/sdk/ndk/21.3.6528147/
91 | ```
92 |
93 | - Install [cargo ndk](https://github.com/bbqsrc/cargo-ndk):
94 |
95 | ```
96 | cargo install cargo-ndk
97 | ```
98 |
99 | - Add targets
100 |
101 | ```
102 | rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
103 | ```
104 |
105 | - Run the project in Android Studio. This will build Rust, put the binaries in the correct place and start the app.
106 |
107 | ## iOS specific steps
108 |
109 | - Install rust-bitcode 1.46.0 with macOS binary support
110 |
111 | ```
112 | wget https://github.com/getditto/rust-bitcode/releases/download/v1.46.0/rust-ios-arm64-1.46.0.zip
113 | unzip rust-ios-arm64-1.46.0.zip
114 | cd rust-ios-arm64-1.46.0
115 | ./install.sh
116 | ```
117 |
118 | As the binaries are not signed, you'll have to convince macOS that it's safe to run them.
119 | One solution is to do the following:
120 |
121 | 1. `cd rust_android_ios/ios_app`
122 | 2. `cargo +ios-arm64-1.46.0 build --target aarch64-apple-ios --release --lib`
123 | 3. if it fails because macOS doesn't trust the binary, go to
124 | `System Preferences -> Security & Privacy` and `Allow to run binary`
125 | then go to 2.
126 |
127 | - Run the project in Xcode. This will build Rust, put the binaries in the correct place and start the app.
128 |
129 | ## Android specifics
130 |
131 | - Logcat doesn't show stdout and stderr, which means that you'll not see `println` or `panic` messages (unless specially configured, like done in this repo).
132 | - If you're having difficulties, try reproducing the problem in a plain (non Android) Kotlin (or Java) project. The JNI is the same, but it's easier to debug, among other things, because you can see stdout/stderr.
133 |
134 | ## iOS
135 |
136 | - iOS shows stdout/stderr as expected and is overall easier to worth with than Android, given the simpler FFI api.
137 |
138 | ## Inspecting binaries
139 |
140 | There are diverse tools to inspect the binaries, e.g.
141 |
142 | ```
143 | nm -g libcore.so
144 | ```
145 |
146 | Shows the external symbols, useful if you want to check that the library was generated correctly / contains the symbols from your sources.
147 |
148 | To look for a specific symbol:
149 |
150 | ```
151 | nm -g libcore.so | grep greet
152 | ```
153 |
154 | # Convenience
155 |
156 | ## iOS
157 |
158 | - [cbindgen](https://github.com/eqrion/cbindgen): generates headers for the FFI Rust declarations. In this project, this would mean that `mobileapp-ios.h` would be automatically generated.
159 |
160 | ## Android
161 |
162 | - [rust-swig](https://github.com/Dushistov/flapigen-rs): similarly to cbindgen for iOS, this generates the JNI api for the Rust declarations. In this project, this would mean that `JNIApi` would be generated, and `ffi_android.rs` mostly too.
163 |
164 | # Links
165 |
166 | [Official Rust FFI docs](https://doc.rust-lang.org/nomicon/ffi.html)
167 |
168 | [Rust FFI guide](https://michael-f-bryan.github.io/rust-ffi-guide/)
169 |
170 | [Official JNI docs](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html) (tutorials may be better to start...)
171 |
172 | [Android JNI tips](https://developer.android.com/training/articles/perf-jni)
173 |
174 | [Android supported ABIs](https://developer.android.com/ndk/guides/abis)
175 |
176 | # Contribute
177 |
178 | 1. Fork
179 | 2. Commit changes to a branch in your fork
180 | 3. Push your code and make a pull request
181 |
182 |
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "aho-corasick"
5 | version = "0.7.6"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | dependencies = [
8 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
9 | ]
10 |
11 | [[package]]
12 | name = "android_log-sys"
13 | version = "0.1.2"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 |
16 | [[package]]
17 | name = "android_logger"
18 | version = "0.8.6"
19 | source = "registry+https://github.com/rust-lang/crates.io-index"
20 | dependencies = [
21 | "android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
22 | "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
23 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
24 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
25 | ]
26 |
27 | [[package]]
28 | name = "ascii"
29 | version = "0.9.3"
30 | source = "registry+https://github.com/rust-lang/crates.io-index"
31 |
32 | [[package]]
33 | name = "atty"
34 | version = "0.2.13"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | dependencies = [
37 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
38 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
39 | ]
40 |
41 | [[package]]
42 | name = "byteorder"
43 | version = "1.3.4"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 |
46 | [[package]]
47 | name = "cesu8"
48 | version = "1.1.0"
49 | source = "registry+https://github.com/rust-lang/crates.io-index"
50 |
51 | [[package]]
52 | name = "cfg-if"
53 | version = "0.1.9"
54 | source = "registry+https://github.com/rust-lang/crates.io-index"
55 |
56 | [[package]]
57 | name = "combine"
58 | version = "3.8.1"
59 | source = "registry+https://github.com/rust-lang/crates.io-index"
60 | dependencies = [
61 | "ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
62 | "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
63 | "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
64 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
65 | "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
66 | ]
67 |
68 | [[package]]
69 | name = "core-foundation"
70 | version = "0.6.4"
71 | source = "registry+https://github.com/rust-lang/crates.io-index"
72 | dependencies = [
73 | "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
74 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
75 | ]
76 |
77 | [[package]]
78 | name = "core-foundation-sys"
79 | version = "0.6.2"
80 | source = "registry+https://github.com/rust-lang/crates.io-index"
81 |
82 | [[package]]
83 | name = "either"
84 | version = "1.5.3"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 |
87 | [[package]]
88 | name = "env_logger"
89 | version = "0.6.2"
90 | source = "registry+https://github.com/rust-lang/crates.io-index"
91 | dependencies = [
92 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
93 | "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
94 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
95 | "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
96 | "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
97 | ]
98 |
99 | [[package]]
100 | name = "env_logger"
101 | version = "0.7.1"
102 | source = "registry+https://github.com/rust-lang/crates.io-index"
103 | dependencies = [
104 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
105 | "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
106 | ]
107 |
108 | [[package]]
109 | name = "error-chain"
110 | version = "0.12.2"
111 | source = "registry+https://github.com/rust-lang/crates.io-index"
112 | dependencies = [
113 | "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
114 | ]
115 |
116 | [[package]]
117 | name = "humantime"
118 | version = "1.2.0"
119 | source = "registry+https://github.com/rust-lang/crates.io-index"
120 | dependencies = [
121 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
122 | ]
123 |
124 | [[package]]
125 | name = "jni"
126 | version = "0.16.0"
127 | source = "registry+https://github.com/rust-lang/crates.io-index"
128 | dependencies = [
129 | "cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
130 | "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
131 | "error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)",
132 | "jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
133 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
134 | "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
135 | ]
136 |
137 | [[package]]
138 | name = "jni-sys"
139 | version = "0.3.0"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 |
142 | [[package]]
143 | name = "lazy_static"
144 | version = "1.3.0"
145 | source = "registry+https://github.com/rust-lang/crates.io-index"
146 |
147 | [[package]]
148 | name = "libc"
149 | version = "0.2.60"
150 | source = "registry+https://github.com/rust-lang/crates.io-index"
151 |
152 | [[package]]
153 | name = "log"
154 | version = "0.4.8"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | dependencies = [
157 | "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
158 | ]
159 |
160 | [[package]]
161 | name = "log-panics"
162 | version = "2.0.0"
163 | source = "registry+https://github.com/rust-lang/crates.io-index"
164 | dependencies = [
165 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
166 | ]
167 |
168 | [[package]]
169 | name = "memchr"
170 | version = "2.2.1"
171 | source = "registry+https://github.com/rust-lang/crates.io-index"
172 |
173 | [[package]]
174 | name = "quick-error"
175 | version = "1.2.2"
176 | source = "registry+https://github.com/rust-lang/crates.io-index"
177 |
178 | [[package]]
179 | name = "regex"
180 | version = "1.2.1"
181 | source = "registry+https://github.com/rust-lang/crates.io-index"
182 | dependencies = [
183 | "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
184 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
185 | "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
186 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
187 | ]
188 |
189 | [[package]]
190 | name = "regex-syntax"
191 | version = "0.6.11"
192 | source = "registry+https://github.com/rust-lang/crates.io-index"
193 |
194 | [[package]]
195 | name = "rust_android_ios"
196 | version = "0.0.1"
197 | dependencies = [
198 | "android_logger 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
199 | "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
200 | "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
201 | "jni 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
202 | "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
203 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
204 | "log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
205 | ]
206 |
207 | [[package]]
208 | name = "same-file"
209 | version = "1.0.6"
210 | source = "registry+https://github.com/rust-lang/crates.io-index"
211 | dependencies = [
212 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
213 | ]
214 |
215 | [[package]]
216 | name = "termcolor"
217 | version = "1.0.5"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | dependencies = [
220 | "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
221 | ]
222 |
223 | [[package]]
224 | name = "thread_local"
225 | version = "0.3.6"
226 | source = "registry+https://github.com/rust-lang/crates.io-index"
227 | dependencies = [
228 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
229 | ]
230 |
231 | [[package]]
232 | name = "unreachable"
233 | version = "1.0.0"
234 | source = "registry+https://github.com/rust-lang/crates.io-index"
235 | dependencies = [
236 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
237 | ]
238 |
239 | [[package]]
240 | name = "version_check"
241 | version = "0.9.2"
242 | source = "registry+https://github.com/rust-lang/crates.io-index"
243 |
244 | [[package]]
245 | name = "void"
246 | version = "1.0.2"
247 | source = "registry+https://github.com/rust-lang/crates.io-index"
248 |
249 | [[package]]
250 | name = "walkdir"
251 | version = "2.3.1"
252 | source = "registry+https://github.com/rust-lang/crates.io-index"
253 | dependencies = [
254 | "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
255 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
256 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
257 | ]
258 |
259 | [[package]]
260 | name = "winapi"
261 | version = "0.3.7"
262 | source = "registry+https://github.com/rust-lang/crates.io-index"
263 | dependencies = [
264 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
265 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
266 | ]
267 |
268 | [[package]]
269 | name = "winapi-i686-pc-windows-gnu"
270 | version = "0.4.0"
271 | source = "registry+https://github.com/rust-lang/crates.io-index"
272 |
273 | [[package]]
274 | name = "winapi-util"
275 | version = "0.1.2"
276 | source = "registry+https://github.com/rust-lang/crates.io-index"
277 | dependencies = [
278 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
279 | ]
280 |
281 | [[package]]
282 | name = "winapi-x86_64-pc-windows-gnu"
283 | version = "0.4.0"
284 | source = "registry+https://github.com/rust-lang/crates.io-index"
285 |
286 | [[package]]
287 | name = "wincolor"
288 | version = "1.0.1"
289 | source = "registry+https://github.com/rust-lang/crates.io-index"
290 | dependencies = [
291 | "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
292 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
293 | ]
294 |
295 | [metadata]
296 | "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
297 | "checksum android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e"
298 | "checksum android_logger 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8cbd542dd180566fad88fd2729a53a62a734843c626638006a9d63ec0688484e"
299 | "checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
300 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
301 | "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
302 | "checksum cesu8 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
303 | "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
304 | "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
305 | "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
306 | "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
307 | "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
308 | "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
309 | "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
310 | "checksum error-chain 0.12.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd"
311 | "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
312 | "checksum jni 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22bbdc25b49340bc4fc3d9c96dd84d878c4beeca35e3651efa53db51a68d7d4d"
313 | "checksum jni-sys 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
314 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
315 | "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
316 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
317 | "checksum log-panics 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae0136257df209261daa18d6c16394757c63e032e27aafd8b07788b051082bef"
318 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
319 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
320 | "checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26"
321 | "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
322 | "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
323 | "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
324 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
325 | "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
326 | "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
327 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
328 | "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
329 | "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
330 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
331 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
332 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
333 | "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
334 |
--------------------------------------------------------------------------------
/ios_app/ios_app.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8466613B24B3794400E5FBF9 /* libcore in Frameworks */ = {isa = PBXBuildFile; fileRef = 8466613A24B3794400E5FBF9 /* libcore */; };
11 | 84B0672322F9B3FE006DDC18 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B0672222F9B3FE006DDC18 /* AppDelegate.swift */; };
12 | 84B0672522F9B3FE006DDC18 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B0672422F9B3FE006DDC18 /* ViewController.swift */; };
13 | 84B0672822F9B3FE006DDC18 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84B0672622F9B3FE006DDC18 /* Main.storyboard */; };
14 | 84B0672A22F9B3FF006DDC18 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84B0672922F9B3FF006DDC18 /* Assets.xcassets */; };
15 | 84B0672D22F9B3FF006DDC18 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84B0672B22F9B3FF006DDC18 /* LaunchScreen.storyboard */; };
16 | 84B0673822F9B400006DDC18 /* ios_appTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84B0673722F9B400006DDC18 /* ios_appTests.swift */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXContainerItemProxy section */
20 | 84B0673422F9B400006DDC18 /* PBXContainerItemProxy */ = {
21 | isa = PBXContainerItemProxy;
22 | containerPortal = 84B0671722F9B3FE006DDC18 /* Project object */;
23 | proxyType = 1;
24 | remoteGlobalIDString = 84B0671E22F9B3FE006DDC18;
25 | remoteInfo = ios_app;
26 | };
27 | 84B0678822F9F8C6006DDC18 /* PBXContainerItemProxy */ = {
28 | isa = PBXContainerItemProxy;
29 | containerPortal = 84B0671722F9B3FE006DDC18 /* Project object */;
30 | proxyType = 1;
31 | remoteGlobalIDString = 84B0678222F9E9F2006DDC18;
32 | remoteInfo = mobcore;
33 | };
34 | /* End PBXContainerItemProxy section */
35 |
36 | /* Begin PBXCopyFilesBuildPhase section */
37 | 84B0677E22F9E9D4006DDC18 /* Embed Frameworks */ = {
38 | isa = PBXCopyFilesBuildPhase;
39 | buildActionMask = 2147483647;
40 | dstPath = "";
41 | dstSubfolderSpec = 10;
42 | files = (
43 | );
44 | name = "Embed Frameworks";
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXCopyFilesBuildPhase section */
48 |
49 | /* Begin PBXFileReference section */
50 | 8466613624B3789200E5FBF9 /* mobileapp-ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mobileapp-ios.h"; sourceTree = ""; };
51 | 8466613A24B3794400E5FBF9 /* libcore */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libcore; sourceTree = ""; };
52 | 84B0671F22F9B3FE006DDC18 /* ios_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ios_app.app; sourceTree = BUILT_PRODUCTS_DIR; };
53 | 84B0672222F9B3FE006DDC18 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
54 | 84B0672422F9B3FE006DDC18 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
55 | 84B0672722F9B3FE006DDC18 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
56 | 84B0672922F9B3FF006DDC18 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
57 | 84B0672C22F9B3FF006DDC18 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
58 | 84B0672E22F9B3FF006DDC18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
59 | 84B0673322F9B400006DDC18 /* ios_appTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ios_appTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
60 | 84B0673722F9B400006DDC18 /* ios_appTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ios_appTests.swift; sourceTree = ""; };
61 | 84B0673922F9B400006DDC18 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
62 | 84B0675022F9E3C7006DDC18 /* Rust-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Rust-Bridging-Header.h"; sourceTree = ""; };
63 | 84B0675122F9E4DF006DDC18 /* build-rust-xcode.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "build-rust-xcode.sh"; sourceTree = ""; };
64 | /* End PBXFileReference section */
65 |
66 | /* Begin PBXFrameworksBuildPhase section */
67 | 84B0671C22F9B3FE006DDC18 /* Frameworks */ = {
68 | isa = PBXFrameworksBuildPhase;
69 | buildActionMask = 2147483647;
70 | files = (
71 | 8466613B24B3794400E5FBF9 /* libcore in Frameworks */,
72 | );
73 | runOnlyForDeploymentPostprocessing = 0;
74 | };
75 | 84B0673022F9B400006DDC18 /* Frameworks */ = {
76 | isa = PBXFrameworksBuildPhase;
77 | buildActionMask = 2147483647;
78 | files = (
79 | );
80 | runOnlyForDeploymentPostprocessing = 0;
81 | };
82 | /* End PBXFrameworksBuildPhase section */
83 |
84 | /* Begin PBXGroup section */
85 | 8466613424B3789200E5FBF9 /* core */ = {
86 | isa = PBXGroup;
87 | children = (
88 | 8466613A24B3794400E5FBF9 /* libcore */,
89 | 8466613624B3789200E5FBF9 /* mobileapp-ios.h */,
90 | );
91 | path = core;
92 | sourceTree = "";
93 | };
94 | 84B0671622F9B3FE006DDC18 = {
95 | isa = PBXGroup;
96 | children = (
97 | 8466613424B3789200E5FBF9 /* core */,
98 | 84B0675022F9E3C7006DDC18 /* Rust-Bridging-Header.h */,
99 | 84B0675122F9E4DF006DDC18 /* build-rust-xcode.sh */,
100 | 84B0672122F9B3FE006DDC18 /* ios_app */,
101 | 84B0673622F9B400006DDC18 /* ios_appTests */,
102 | 84B0672022F9B3FE006DDC18 /* Products */,
103 | 84B0678E22FA195A006DDC18 /* Frameworks */,
104 | );
105 | sourceTree = "";
106 | };
107 | 84B0672022F9B3FE006DDC18 /* Products */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 84B0671F22F9B3FE006DDC18 /* ios_app.app */,
111 | 84B0673322F9B400006DDC18 /* ios_appTests.xctest */,
112 | );
113 | name = Products;
114 | sourceTree = "";
115 | };
116 | 84B0672122F9B3FE006DDC18 /* ios_app */ = {
117 | isa = PBXGroup;
118 | children = (
119 | 84B0672222F9B3FE006DDC18 /* AppDelegate.swift */,
120 | 84B0672422F9B3FE006DDC18 /* ViewController.swift */,
121 | 84B0672622F9B3FE006DDC18 /* Main.storyboard */,
122 | 84B0672922F9B3FF006DDC18 /* Assets.xcassets */,
123 | 84B0672B22F9B3FF006DDC18 /* LaunchScreen.storyboard */,
124 | 84B0672E22F9B3FF006DDC18 /* Info.plist */,
125 | );
126 | path = ios_app;
127 | sourceTree = "";
128 | };
129 | 84B0673622F9B400006DDC18 /* ios_appTests */ = {
130 | isa = PBXGroup;
131 | children = (
132 | 84B0673722F9B400006DDC18 /* ios_appTests.swift */,
133 | 84B0673922F9B400006DDC18 /* Info.plist */,
134 | );
135 | path = ios_appTests;
136 | sourceTree = "";
137 | };
138 | 84B0678E22FA195A006DDC18 /* Frameworks */ = {
139 | isa = PBXGroup;
140 | children = (
141 | );
142 | name = Frameworks;
143 | sourceTree = "";
144 | };
145 | /* End PBXGroup section */
146 |
147 | /* Begin PBXLegacyTarget section */
148 | 84B0678222F9E9F2006DDC18 /* mobcore */ = {
149 | isa = PBXLegacyTarget;
150 | buildArgumentsString = "\"$(SRCROOT)/build-rust-xcode.sh\"";
151 | buildConfigurationList = 84B0678322F9E9F2006DDC18 /* Build configuration list for PBXLegacyTarget "mobcore" */;
152 | buildPhases = (
153 | );
154 | buildToolPath = /bin/bash;
155 | buildWorkingDirectory = ../;
156 | dependencies = (
157 | );
158 | name = mobcore;
159 | passBuildSettingsInEnvironment = 1;
160 | productName = sdfs;
161 | };
162 | /* End PBXLegacyTarget section */
163 |
164 | /* Begin PBXNativeTarget section */
165 | 84B0671E22F9B3FE006DDC18 /* ios_app */ = {
166 | isa = PBXNativeTarget;
167 | buildConfigurationList = 84B0674722F9B400006DDC18 /* Build configuration list for PBXNativeTarget "ios_app" */;
168 | buildPhases = (
169 | 84B0671B22F9B3FE006DDC18 /* Sources */,
170 | 84B0671C22F9B3FE006DDC18 /* Frameworks */,
171 | 84B0671D22F9B3FE006DDC18 /* Resources */,
172 | 84B0677E22F9E9D4006DDC18 /* Embed Frameworks */,
173 | );
174 | buildRules = (
175 | );
176 | dependencies = (
177 | 84B0678922F9F8C6006DDC18 /* PBXTargetDependency */,
178 | );
179 | name = ios_app;
180 | productName = ios_app;
181 | productReference = 84B0671F22F9B3FE006DDC18 /* ios_app.app */;
182 | productType = "com.apple.product-type.application";
183 | };
184 | 84B0673222F9B400006DDC18 /* ios_appTests */ = {
185 | isa = PBXNativeTarget;
186 | buildConfigurationList = 84B0674A22F9B400006DDC18 /* Build configuration list for PBXNativeTarget "ios_appTests" */;
187 | buildPhases = (
188 | 84B0672F22F9B400006DDC18 /* Sources */,
189 | 84B0673022F9B400006DDC18 /* Frameworks */,
190 | 84B0673122F9B400006DDC18 /* Resources */,
191 | );
192 | buildRules = (
193 | );
194 | dependencies = (
195 | 84B0673522F9B400006DDC18 /* PBXTargetDependency */,
196 | );
197 | name = ios_appTests;
198 | productName = ios_appTests;
199 | productReference = 84B0673322F9B400006DDC18 /* ios_appTests.xctest */;
200 | productType = "com.apple.product-type.bundle.unit-test";
201 | };
202 | /* End PBXNativeTarget section */
203 |
204 | /* Begin PBXProject section */
205 | 84B0671722F9B3FE006DDC18 /* Project object */ = {
206 | isa = PBXProject;
207 | attributes = {
208 | LastSwiftUpdateCheck = 1030;
209 | LastUpgradeCheck = 1250;
210 | ORGANIZATIONNAME = com.schuetz;
211 | TargetAttributes = {
212 | 84B0671E22F9B3FE006DDC18 = {
213 | CreatedOnToolsVersion = 10.3;
214 | };
215 | 84B0673222F9B400006DDC18 = {
216 | CreatedOnToolsVersion = 10.3;
217 | TestTargetID = 84B0671E22F9B3FE006DDC18;
218 | };
219 | 84B0678222F9E9F2006DDC18 = {
220 | CreatedOnToolsVersion = 10.3;
221 | };
222 | };
223 | };
224 | buildConfigurationList = 84B0671A22F9B3FE006DDC18 /* Build configuration list for PBXProject "ios_app" */;
225 | compatibilityVersion = "Xcode 9.3";
226 | developmentRegion = en;
227 | hasScannedForEncodings = 0;
228 | knownRegions = (
229 | en,
230 | Base,
231 | );
232 | mainGroup = 84B0671622F9B3FE006DDC18;
233 | productRefGroup = 84B0672022F9B3FE006DDC18 /* Products */;
234 | projectDirPath = "";
235 | projectRoot = "";
236 | targets = (
237 | 84B0671E22F9B3FE006DDC18 /* ios_app */,
238 | 84B0673222F9B400006DDC18 /* ios_appTests */,
239 | 84B0678222F9E9F2006DDC18 /* mobcore */,
240 | );
241 | };
242 | /* End PBXProject section */
243 |
244 | /* Begin PBXResourcesBuildPhase section */
245 | 84B0671D22F9B3FE006DDC18 /* Resources */ = {
246 | isa = PBXResourcesBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 84B0672D22F9B3FF006DDC18 /* LaunchScreen.storyboard in Resources */,
250 | 84B0672A22F9B3FF006DDC18 /* Assets.xcassets in Resources */,
251 | 84B0672822F9B3FE006DDC18 /* Main.storyboard in Resources */,
252 | );
253 | runOnlyForDeploymentPostprocessing = 0;
254 | };
255 | 84B0673122F9B400006DDC18 /* Resources */ = {
256 | isa = PBXResourcesBuildPhase;
257 | buildActionMask = 2147483647;
258 | files = (
259 | );
260 | runOnlyForDeploymentPostprocessing = 0;
261 | };
262 | /* End PBXResourcesBuildPhase section */
263 |
264 | /* Begin PBXSourcesBuildPhase section */
265 | 84B0671B22F9B3FE006DDC18 /* Sources */ = {
266 | isa = PBXSourcesBuildPhase;
267 | buildActionMask = 2147483647;
268 | files = (
269 | 84B0672522F9B3FE006DDC18 /* ViewController.swift in Sources */,
270 | 84B0672322F9B3FE006DDC18 /* AppDelegate.swift in Sources */,
271 | );
272 | runOnlyForDeploymentPostprocessing = 0;
273 | };
274 | 84B0672F22F9B400006DDC18 /* Sources */ = {
275 | isa = PBXSourcesBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | 84B0673822F9B400006DDC18 /* ios_appTests.swift in Sources */,
279 | );
280 | runOnlyForDeploymentPostprocessing = 0;
281 | };
282 | /* End PBXSourcesBuildPhase section */
283 |
284 | /* Begin PBXTargetDependency section */
285 | 84B0673522F9B400006DDC18 /* PBXTargetDependency */ = {
286 | isa = PBXTargetDependency;
287 | target = 84B0671E22F9B3FE006DDC18 /* ios_app */;
288 | targetProxy = 84B0673422F9B400006DDC18 /* PBXContainerItemProxy */;
289 | };
290 | 84B0678922F9F8C6006DDC18 /* PBXTargetDependency */ = {
291 | isa = PBXTargetDependency;
292 | target = 84B0678222F9E9F2006DDC18 /* mobcore */;
293 | targetProxy = 84B0678822F9F8C6006DDC18 /* PBXContainerItemProxy */;
294 | };
295 | /* End PBXTargetDependency section */
296 |
297 | /* Begin PBXVariantGroup section */
298 | 84B0672622F9B3FE006DDC18 /* Main.storyboard */ = {
299 | isa = PBXVariantGroup;
300 | children = (
301 | 84B0672722F9B3FE006DDC18 /* Base */,
302 | );
303 | name = Main.storyboard;
304 | sourceTree = "";
305 | };
306 | 84B0672B22F9B3FF006DDC18 /* LaunchScreen.storyboard */ = {
307 | isa = PBXVariantGroup;
308 | children = (
309 | 84B0672C22F9B3FF006DDC18 /* Base */,
310 | );
311 | name = LaunchScreen.storyboard;
312 | sourceTree = "";
313 | };
314 | /* End PBXVariantGroup section */
315 |
316 | /* Begin XCBuildConfiguration section */
317 | 84B0674522F9B400006DDC18 /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | ALWAYS_SEARCH_USER_PATHS = NO;
321 | CLANG_ANALYZER_NONNULL = YES;
322 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
323 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
324 | CLANG_CXX_LIBRARY = "libc++";
325 | CLANG_ENABLE_MODULES = YES;
326 | CLANG_ENABLE_OBJC_ARC = YES;
327 | CLANG_ENABLE_OBJC_WEAK = YES;
328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
329 | CLANG_WARN_BOOL_CONVERSION = YES;
330 | CLANG_WARN_COMMA = YES;
331 | CLANG_WARN_CONSTANT_CONVERSION = YES;
332 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
334 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
335 | CLANG_WARN_EMPTY_BODY = YES;
336 | CLANG_WARN_ENUM_CONVERSION = YES;
337 | CLANG_WARN_INFINITE_RECURSION = YES;
338 | CLANG_WARN_INT_CONVERSION = YES;
339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
340 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
341 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
343 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
345 | CLANG_WARN_STRICT_PROTOTYPES = YES;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
348 | CLANG_WARN_UNREACHABLE_CODE = YES;
349 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
350 | CODE_SIGN_IDENTITY = "iPhone Developer";
351 | COPY_PHASE_STRIP = NO;
352 | DEBUG_INFORMATION_FORMAT = dwarf;
353 | ENABLE_STRICT_OBJC_MSGSEND = YES;
354 | ENABLE_TESTABILITY = YES;
355 | GCC_C_LANGUAGE_STANDARD = gnu11;
356 | GCC_DYNAMIC_NO_PIC = NO;
357 | GCC_NO_COMMON_BLOCKS = YES;
358 | GCC_OPTIMIZATION_LEVEL = 0;
359 | GCC_PREPROCESSOR_DEFINITIONS = (
360 | "DEBUG=1",
361 | "$(inherited)",
362 | );
363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
365 | GCC_WARN_UNDECLARED_SELECTOR = YES;
366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
367 | GCC_WARN_UNUSED_FUNCTION = YES;
368 | GCC_WARN_UNUSED_VARIABLE = YES;
369 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
370 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
371 | MTL_FAST_MATH = YES;
372 | ONLY_ACTIVE_ARCH = YES;
373 | SDKROOT = iphoneos;
374 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
375 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
376 | };
377 | name = Debug;
378 | };
379 | 84B0674622F9B400006DDC18 /* Release */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | ALWAYS_SEARCH_USER_PATHS = NO;
383 | CLANG_ANALYZER_NONNULL = YES;
384 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
386 | CLANG_CXX_LIBRARY = "libc++";
387 | CLANG_ENABLE_MODULES = YES;
388 | CLANG_ENABLE_OBJC_ARC = YES;
389 | CLANG_ENABLE_OBJC_WEAK = YES;
390 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
391 | CLANG_WARN_BOOL_CONVERSION = YES;
392 | CLANG_WARN_COMMA = YES;
393 | CLANG_WARN_CONSTANT_CONVERSION = YES;
394 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
395 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
396 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
397 | CLANG_WARN_EMPTY_BODY = YES;
398 | CLANG_WARN_ENUM_CONVERSION = YES;
399 | CLANG_WARN_INFINITE_RECURSION = YES;
400 | CLANG_WARN_INT_CONVERSION = YES;
401 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
402 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
403 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
404 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
405 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
406 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
407 | CLANG_WARN_STRICT_PROTOTYPES = YES;
408 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
409 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
410 | CLANG_WARN_UNREACHABLE_CODE = YES;
411 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
412 | CODE_SIGN_IDENTITY = "iPhone Developer";
413 | COPY_PHASE_STRIP = NO;
414 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
415 | ENABLE_NS_ASSERTIONS = NO;
416 | ENABLE_STRICT_OBJC_MSGSEND = YES;
417 | GCC_C_LANGUAGE_STANDARD = gnu11;
418 | GCC_NO_COMMON_BLOCKS = YES;
419 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
420 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
421 | GCC_WARN_UNDECLARED_SELECTOR = YES;
422 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
423 | GCC_WARN_UNUSED_FUNCTION = YES;
424 | GCC_WARN_UNUSED_VARIABLE = YES;
425 | IPHONEOS_DEPLOYMENT_TARGET = 12.4;
426 | MTL_ENABLE_DEBUG_INFO = NO;
427 | MTL_FAST_MATH = YES;
428 | SDKROOT = iphoneos;
429 | SWIFT_COMPILATION_MODE = wholemodule;
430 | SWIFT_OPTIMIZATION_LEVEL = "-O";
431 | VALIDATE_PRODUCT = YES;
432 | };
433 | name = Release;
434 | };
435 | 84B0674822F9B400006DDC18 /* Debug */ = {
436 | isa = XCBuildConfiguration;
437 | buildSettings = {
438 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
439 | CODE_SIGN_STYLE = Automatic;
440 | DEVELOPMENT_TEAM = 37QAPDY2PR;
441 | INFOPLIST_FILE = ios_app/Info.plist;
442 | LD_RUNPATH_SEARCH_PATHS = (
443 | "$(inherited)",
444 | "@executable_path/Frameworks",
445 | );
446 | LIBRARY_SEARCH_PATHS = (
447 | "$(inherited)",
448 | "$(PROJECT_DIR)",
449 | "$(PROJECT_DIR)/core",
450 | );
451 | PRODUCT_BUNDLE_IDENTIFIER = "com.schuetz.ios-app";
452 | PRODUCT_NAME = "$(TARGET_NAME)";
453 | SWIFT_OBJC_BRIDGING_HEADER = "Rust-Bridging-Header.h";
454 | SWIFT_VERSION = 5.0;
455 | TARGETED_DEVICE_FAMILY = "1,2";
456 | };
457 | name = Debug;
458 | };
459 | 84B0674922F9B400006DDC18 /* Release */ = {
460 | isa = XCBuildConfiguration;
461 | buildSettings = {
462 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
463 | CODE_SIGN_STYLE = Automatic;
464 | DEVELOPMENT_TEAM = 37QAPDY2PR;
465 | INFOPLIST_FILE = ios_app/Info.plist;
466 | LD_RUNPATH_SEARCH_PATHS = (
467 | "$(inherited)",
468 | "@executable_path/Frameworks",
469 | );
470 | LIBRARY_SEARCH_PATHS = (
471 | "$(inherited)",
472 | "$(PROJECT_DIR)",
473 | "$(PROJECT_DIR)/core",
474 | );
475 | ONLY_ACTIVE_ARCH = YES;
476 | PRODUCT_BUNDLE_IDENTIFIER = "com.schuetz.ios-app";
477 | PRODUCT_NAME = "$(TARGET_NAME)";
478 | SWIFT_OBJC_BRIDGING_HEADER = "Rust-Bridging-Header.h";
479 | SWIFT_VERSION = 5.0;
480 | TARGETED_DEVICE_FAMILY = "1,2";
481 | };
482 | name = Release;
483 | };
484 | 84B0674B22F9B400006DDC18 /* Debug */ = {
485 | isa = XCBuildConfiguration;
486 | buildSettings = {
487 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
488 | BUNDLE_LOADER = "$(TEST_HOST)";
489 | CODE_SIGN_STYLE = Automatic;
490 | DEVELOPMENT_TEAM = 37QAPDY2PR;
491 | INFOPLIST_FILE = ios_appTests/Info.plist;
492 | LD_RUNPATH_SEARCH_PATHS = (
493 | "$(inherited)",
494 | "@executable_path/Frameworks",
495 | "@loader_path/Frameworks",
496 | );
497 | PRODUCT_BUNDLE_IDENTIFIER = "com.schuetz.ios-appTests";
498 | PRODUCT_NAME = "$(TARGET_NAME)";
499 | SWIFT_VERSION = 5.0;
500 | TARGETED_DEVICE_FAMILY = "1,2";
501 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ios_app.app/ios_app";
502 | };
503 | name = Debug;
504 | };
505 | 84B0674C22F9B400006DDC18 /* Release */ = {
506 | isa = XCBuildConfiguration;
507 | buildSettings = {
508 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
509 | BUNDLE_LOADER = "$(TEST_HOST)";
510 | CODE_SIGN_STYLE = Automatic;
511 | DEVELOPMENT_TEAM = 37QAPDY2PR;
512 | INFOPLIST_FILE = ios_appTests/Info.plist;
513 | LD_RUNPATH_SEARCH_PATHS = (
514 | "$(inherited)",
515 | "@executable_path/Frameworks",
516 | "@loader_path/Frameworks",
517 | );
518 | PRODUCT_BUNDLE_IDENTIFIER = "com.schuetz.ios-appTests";
519 | PRODUCT_NAME = "$(TARGET_NAME)";
520 | SWIFT_VERSION = 5.0;
521 | TARGETED_DEVICE_FAMILY = "1,2";
522 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ios_app.app/ios_app";
523 | };
524 | name = Release;
525 | };
526 | 84B0678422F9E9F2006DDC18 /* Debug */ = {
527 | isa = XCBuildConfiguration;
528 | buildSettings = {
529 | CODE_SIGN_STYLE = Automatic;
530 | DEBUGGING_SYMBOLS = YES;
531 | DEBUG_INFORMATION_FORMAT = dwarf;
532 | DEVELOPMENT_TEAM = 37QAPDY2PR;
533 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
534 | GCC_OPTIMIZATION_LEVEL = 0;
535 | OTHER_CFLAGS = "";
536 | OTHER_LDFLAGS = "";
537 | PRODUCT_NAME = "$(TARGET_NAME)";
538 | };
539 | name = Debug;
540 | };
541 | 84B0678522F9E9F2006DDC18 /* Release */ = {
542 | isa = XCBuildConfiguration;
543 | buildSettings = {
544 | CODE_SIGN_STYLE = Automatic;
545 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
546 | DEVELOPMENT_TEAM = 37QAPDY2PR;
547 | OTHER_CFLAGS = "";
548 | OTHER_LDFLAGS = "";
549 | PRODUCT_NAME = "$(TARGET_NAME)";
550 | };
551 | name = Release;
552 | };
553 | /* End XCBuildConfiguration section */
554 |
555 | /* Begin XCConfigurationList section */
556 | 84B0671A22F9B3FE006DDC18 /* Build configuration list for PBXProject "ios_app" */ = {
557 | isa = XCConfigurationList;
558 | buildConfigurations = (
559 | 84B0674522F9B400006DDC18 /* Debug */,
560 | 84B0674622F9B400006DDC18 /* Release */,
561 | );
562 | defaultConfigurationIsVisible = 0;
563 | defaultConfigurationName = Release;
564 | };
565 | 84B0674722F9B400006DDC18 /* Build configuration list for PBXNativeTarget "ios_app" */ = {
566 | isa = XCConfigurationList;
567 | buildConfigurations = (
568 | 84B0674822F9B400006DDC18 /* Debug */,
569 | 84B0674922F9B400006DDC18 /* Release */,
570 | );
571 | defaultConfigurationIsVisible = 0;
572 | defaultConfigurationName = Release;
573 | };
574 | 84B0674A22F9B400006DDC18 /* Build configuration list for PBXNativeTarget "ios_appTests" */ = {
575 | isa = XCConfigurationList;
576 | buildConfigurations = (
577 | 84B0674B22F9B400006DDC18 /* Debug */,
578 | 84B0674C22F9B400006DDC18 /* Release */,
579 | );
580 | defaultConfigurationIsVisible = 0;
581 | defaultConfigurationName = Release;
582 | };
583 | 84B0678322F9E9F2006DDC18 /* Build configuration list for PBXLegacyTarget "mobcore" */ = {
584 | isa = XCConfigurationList;
585 | buildConfigurations = (
586 | 84B0678422F9E9F2006DDC18 /* Debug */,
587 | 84B0678522F9E9F2006DDC18 /* Release */,
588 | );
589 | defaultConfigurationIsVisible = 0;
590 | defaultConfigurationName = Release;
591 | };
592 | /* End XCConfigurationList section */
593 | };
594 | rootObject = 84B0671722F9B3FE006DDC18 /* Project object */;
595 | }
596 |
--------------------------------------------------------------------------------