diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6ef1438 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.jar filter=lfs diff=lfs merge=lfs -text +*.webp filter=lfs diff=lfs merge=lfs -text diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8017cd..23b964b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,27 +1,48 @@ -name: Swift +name: Uniffi Builds on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] jobs: - build: - + build_xcframework: runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - name: Build - run: | + - uses: actions/checkout@v2 + - name: Build + run: | make prepare-apple cd hello make all - - name: 'Upload xcframework' - uses: actions/upload-artifact@v2 - with: - name: HelloFFI.xcframework - path: hello/target/HelloFFI.xcframework - retention-days: 7 \ No newline at end of file + - name: "Upload xcframework" + uses: actions/upload-artifact@v2 + with: + name: HelloFFI.xcframework + path: hello/target/HelloFFI.xcframework + retention-days: 7 + + # build_android: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v2 + # with: + # lfs: true + # - uses: actions/setup-java@v2 + # with: + # distribution: 'microsoft' + # java-version: '11' + # - name: Setup Android SDK + # uses: android-actions/setup-android@v2 + # - uses: nttld/setup-ndk@v1 + # with: + # ndk-version: r21e + # - name: "Build Android library" + # env: + # ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + # run: | + # cd hello/platforms/android/UniffiRustExample + # ./gradlew cargoBuild --info diff --git a/hello/.gitignore b/hello/.gitignore index 8321e59..05e3022 100644 --- a/hello/.gitignore +++ b/hello/.gitignore @@ -17,4 +17,5 @@ src/HelloFFI.modulemap src/Hello.swift src/HelloFFI.h -HelloAppleDemoApp.xcodeproj/project.xcworkspace/xcuserdata/wildcat.xcuserdatad +HelloAppleDemoApp.xcodeproj/project.xcworkspace/xcuserdata/*.xcuserdatad +platforms/android/UniffiRustExample/app/src/main/java/uniffi/Hello/Hello.kt diff --git a/hello/Cargo.toml b/hello/Cargo.toml index f0ce0be..cb8c874 100644 --- a/hello/Cargo.toml +++ b/hello/Cargo.toml @@ -5,17 +5,17 @@ edition = "2021" authors = ["Daohan Chong "] [lib] -crate-type = ["staticlib", "cdylib"] name = "hello" +crate-type = ["staticlib", "cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -uniffi = "0.16.0" -uniffi_macros = "0.16.0" +uniffi = "0.17.0" +uniffi_macros = "0.17.0" [build-dependencies] -uniffi_build = "0.16.0" +uniffi_build = "0.17.0" [profile.release] opt-level = 'z' # Optimize for size. diff --git a/hello/Makefile b/hello/Makefile index e8eced2..348a083 100644 --- a/hello/Makefile +++ b/hello/Makefile @@ -18,6 +18,10 @@ bindgen-swift: uniffi-bindgen generate src/hello.udl --language swift sed -i '' 's/module\ HelloFFI/framework\ module\ HelloFFI/' src/HelloFFI.modulemap +bindgen-kotlin: + uniffi-bindgen generate src/hello.udl --language kotlin -o platforms/android/UniffiRustExample/app/src/main/java + sed -i '' 's/return "uniffi_Hello"/return "hello"/' platforms/android/UniffiRustExample/app/src/main/java/uniffi/Hello/Hello.kt + assemble-frameworks: find . -type d -name HelloFFI.framework -exec rm -rf {} \; || echo "rm failed" cd target/x86_64-apple-ios/release && mkdir -p HelloFFI.framework && cd HelloFFI.framework && mkdir Headers Modules Resources && cp ../../../../src/HelloFFI.modulemap ./Modules/module.modulemap && cp ../../../../src/HelloFFI.h ./Headers/HelloFFI.h && cp ../$(STATIC_LIB_NAME) ./HelloFFI && cp ../../../../misc/apple/Info.plist ./Resources diff --git a/hello/platforms/android/UniffiRustExample/.gitignore b/hello/platforms/android/UniffiRustExample/.gitignore new file mode 100644 index 0000000..f3ec74a --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/.gitignore @@ -0,0 +1,12 @@ +*.iml +.gradle +/local.properties +/.idea/ +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties + +*.so diff --git a/hello/platforms/android/UniffiRustExample/app/.gitignore b/hello/platforms/android/UniffiRustExample/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/build.gradle b/hello/platforms/android/UniffiRustExample/app/build.gradle new file mode 100644 index 0000000..041fa8b --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/build.gradle @@ -0,0 +1,74 @@ +plugins { + id 'com.android.application' + id 'org.jetbrains.kotlin.android' + +} + +apply plugin: 'org.mozilla.rust-android-gradle.rust-android' + +cargo { + module = "../../../.." // Or whatever directory contains your Cargo.toml + libname = "hello" // Or whatever matches Cargo.toml's [package] name. + targets = ["arm", "x86", "x86_64", "arm64"] +} + +android { + compileSdk 31 +// ndkVersion rootProject.ext.ndkVersion + + defaultConfig { + applicationId "com.demo.mobile.uniffirustexample" + minSdk 23 + targetSdk 31 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + buildFeatures { + viewBinding true + } +} + +dependencies { + implementation "net.java.dev.jna:jna:5.7.0@aar" + + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' + implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' +} + + +afterEvaluate { + // The `cargoBuild` task isn't available until after evaluation. + android.applicationVariants.all { variant -> + def productFlavor = "" + variant.productFlavors.each { + productFlavor += "${it.name.capitalize()}" + } + def buildType = "${variant.buildType.name.capitalize()}" + tasks["generate${productFlavor}${buildType}Assets"].dependsOn(tasks["cargoBuild"]) + + + } +} diff --git a/hello/platforms/android/UniffiRustExample/app/proguard-rules.pro b/hello/platforms/android/UniffiRustExample/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/example/mobile/demo/uniffirustexample/ExampleInstrumentedTest.kt b/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/example/mobile/demo/uniffirustexample/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..f6d0e68 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/example/mobile/demo/uniffirustexample/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.mobile.demo.uniffirustexample + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.mobile.demo.uniffirustexample", appContext.packageName) + } +} \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/microsoft/tscodegen/demo/uniffirustexample/ExampleInstrumentedTest.kt b/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/microsoft/tscodegen/demo/uniffirustexample/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..f6d0e68 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/androidTest/java/com/microsoft/tscodegen/demo/uniffirustexample/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.example.mobile.demo.uniffirustexample + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.example.mobile.demo.uniffirustexample", appContext.packageName) + } +} \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/AndroidManifest.xml b/hello/platforms/android/UniffiRustExample/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..79ee800 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/FirstFragment.kt b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/FirstFragment.kt new file mode 100644 index 0000000..fb62ab0 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/FirstFragment.kt @@ -0,0 +1,43 @@ +package com.example.mobile.demo.uniffirustexample + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.fragment.findNavController +import com.example.mobile.demo.uniffirustexample.databinding.FragmentFirstBinding + + +/** + * A simple [Fragment] subclass as the default destination in the navigation. + */ +class FirstFragment : Fragment() { + + private var _binding: FragmentFirstBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = FragmentFirstBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.buttonFirst.setOnClickListener { + findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/MainActivity.kt b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/MainActivity.kt new file mode 100644 index 0000000..d0958fa --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/MainActivity.kt @@ -0,0 +1,66 @@ +package com.example.mobile.demo.uniffirustexample + +import android.os.Bundle +import com.google.android.material.snackbar.Snackbar +import androidx.appcompat.app.AppCompatActivity +import androidx.navigation.findNavController +import androidx.navigation.ui.AppBarConfiguration +import androidx.navigation.ui.navigateUp +import androidx.navigation.ui.setupActionBarWithNavController +import android.view.Menu +import android.view.MenuItem +import uniffi.Hello.* +import com.example.mobile.demo.uniffirustexample.databinding.ActivityMainBinding + +class MainActivity : AppCompatActivity() { + + private lateinit var appBarConfiguration: AppBarConfiguration + private lateinit var binding: ActivityMainBinding + + init { + System.loadLibrary("hello") + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + binding = ActivityMainBinding.inflate(layoutInflater) + setContentView(binding.root) + + setSupportActionBar(binding.toolbar) + + val navController = findNavController(R.id.nav_host_fragment_content_main) + appBarConfiguration = AppBarConfiguration(navController.graph) + setupActionBarWithNavController(navController, appBarConfiguration) + + binding.fab.setOnClickListener { view -> + Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) + .setAction("Action", null).show() + } + + val result = rustGreeting("foo") + print(result) + } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { + // Inflate the menu; this adds items to the action bar if it is present. + menuInflater.inflate(R.menu.menu_main, menu) + return true + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + return when (item.itemId) { + R.id.action_settings -> true + else -> super.onOptionsItemSelected(item) + } + } + + override fun onSupportNavigateUp(): Boolean { + val navController = findNavController(R.id.nav_host_fragment_content_main) + return navController.navigateUp(appBarConfiguration) + || super.onSupportNavigateUp() + } +} \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/SecondFragment.kt b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/SecondFragment.kt new file mode 100644 index 0000000..00f89d7 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/java/com/example/mobile/demo/uniffirustexample/SecondFragment.kt @@ -0,0 +1,44 @@ +package com.example.mobile.demo.uniffirustexample + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.navigation.fragment.findNavController +import com.example.mobile.demo.uniffirustexample.databinding.FragmentSecondBinding + +/** + * A simple [Fragment] subclass as the second destination in the navigation. + */ +class SecondFragment : Fragment() { + + private var _binding: FragmentSecondBinding? = null + + // This property is only valid between onCreateView and + // onDestroyView. + private val binding get() = _binding!! + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + + _binding = FragmentSecondBinding.inflate(inflater, container, false) + return binding.root + + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.buttonSecond.setOnClickListener { + findNavController().navigate(R.id.action_SecondFragment_to_FirstFragment) + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable/ic_launcher_background.xml b/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/activity_main.xml b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..25ffa50 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/content_main.xml b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/content_main.xml new file mode 100644 index 0000000..4f68632 --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/content_main.xml @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/fragment_first.xml b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/fragment_first.xml new file mode 100644 index 0000000..fb44a3d --- /dev/null +++ b/hello/platforms/android/UniffiRustExample/app/src/main/res/layout/fragment_first.xml @@ -0,0 +1,28 @@ + + + + + +