mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 11:22:04 +00:00
Merge 9c4e20f988 into 7d01aa0417
This commit is contained in:
commit
2ee0f30c69
156
ANDROID_PLUGIN_LIBRARY_NAME_DOCS.md
Normal file
156
ANDROID_PLUGIN_LIBRARY_NAME_DOCS.md
Normal file
@ -0,0 +1,156 @@
|
||||
# Android Plugin Dynamic Library Name - Documentation Update
|
||||
|
||||
This document provides the updated documentation for the "Calling Rust From Mobile Plugins - Android" section to fix [issue #14569](https://github.com/tauri-apps/tauri/issues/14569).
|
||||
|
||||
## Current Problem
|
||||
|
||||
The current documentation at https://tauri.app/develop/plugins/develop-mobile/#android-1 shows:
|
||||
|
||||
```kotlin
|
||||
System.loadLibrary("app_lib")
|
||||
```
|
||||
|
||||
This hardcoded library name makes plugins non-portable, as developers must manually change `"app_lib"` to match their specific plugin's library name.
|
||||
|
||||
## Proposed Documentation Update
|
||||
|
||||
Replace the current section with the following:
|
||||
|
||||
---
|
||||
|
||||
### Android
|
||||
|
||||
In your plugin's `Cargo.toml`, add the jni crate as a dependency:
|
||||
|
||||
**Cargo.toml**
|
||||
```toml
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
jni = "0.21"
|
||||
```
|
||||
|
||||
#### Understanding the Library Name
|
||||
|
||||
When Cargo builds your plugin for Android, it generates a native library (`.so` file) based on your `Cargo.toml` package name. The library name follows this pattern:
|
||||
|
||||
- **Package name in Cargo.toml**: `tauri-plugin-sample`
|
||||
- **Generated library file**: `libtauri_plugin_sample.so`
|
||||
- **Name for `System.loadLibrary()`**: `tauri_plugin_sample` (without `lib` prefix or `.so` extension)
|
||||
|
||||
Note: Hyphens (`-`) in the package name are converted to underscores (`_`) for the library name.
|
||||
|
||||
#### Loading the Library and Defining Native Functions
|
||||
|
||||
Load your plugin's native library and define external functions in your Kotlin code. In this example, the Kotlin class is `com.example.HelloWorld`, which requires referencing the full package name from the Rust side.
|
||||
|
||||
**Important**: Replace `"your_plugin_lib_name"` with your actual library name derived from your `Cargo.toml` package name.
|
||||
|
||||
**Example.kt**
|
||||
```kotlin
|
||||
package com.example
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class HelloWorld {
|
||||
companion object {
|
||||
private const val TAG = "HelloWorld"
|
||||
|
||||
// Define your plugin's library name based on Cargo.toml package.name
|
||||
// Example: if package name is "tauri-plugin-sample", use "tauri_plugin_sample"
|
||||
private const val LIBRARY_NAME = "your_plugin_lib_name"
|
||||
|
||||
init {
|
||||
try {
|
||||
System.loadLibrary(LIBRARY_NAME)
|
||||
Log.d(TAG, "Successfully loaded lib$LIBRARY_NAME.so")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.e(TAG, "Failed to load lib$LIBRARY_NAME.so", e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
external fun helloWorld(name: String): String?
|
||||
}
|
||||
```
|
||||
|
||||
**Real-world example**: For a plugin with `package.name = "tauri-plugin-sample"` in `Cargo.toml`:
|
||||
|
||||
```kotlin
|
||||
package com.plugin.sample
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class Example {
|
||||
companion object {
|
||||
private const val TAG = "Example"
|
||||
private const val LIBRARY_NAME = "tauri_plugin_sample" // Derived from "tauri-plugin-sample"
|
||||
|
||||
init {
|
||||
try {
|
||||
System.loadLibrary(LIBRARY_NAME)
|
||||
Log.d(TAG, "Successfully loaded libtauri_plugin_sample.so")
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
Log.e(TAG, "Failed to load libtauri_plugin_sample.so", e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
external fun helloWorld(name: String): String?
|
||||
}
|
||||
```
|
||||
|
||||
#### Implementing the Rust JNI Function
|
||||
|
||||
In your plugin's Rust code, define the function JNI will look for. The function name format is `Java_package_class_method`, so for our class above this becomes `Java_com_example_HelloWorld_helloWorld` to get called by our `helloWorld` method:
|
||||
|
||||
**lib.rs**
|
||||
```rust
|
||||
#[cfg(target_os = "android")]
|
||||
#[no_mangle]
|
||||
pub extern "system" fn Java_com_example_HelloWorld_helloWorld(
|
||||
mut env: JNIEnv,
|
||||
_class: JClass,
|
||||
name: JString,
|
||||
) -> jstring {
|
||||
log::debug!("Calling JNI Hello World!");
|
||||
let result = format!("Hello, {}!", name);
|
||||
match env.new_string(result) {
|
||||
Ok(jstr) => jstr.into_raw(),
|
||||
Err(e) => {
|
||||
log::error!("Failed to create JString: {}", e);
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Quick Reference
|
||||
|
||||
To determine your library name:
|
||||
1. Check your `Cargo.toml` `package.name` field
|
||||
2. Replace hyphens with underscores
|
||||
3. Use this as your `LIBRARY_NAME` constant in Kotlin
|
||||
|
||||
| Cargo.toml package.name | Library file | System.loadLibrary() argument |
|
||||
|------------------------|--------------|------------------------------|
|
||||
| `tauri-plugin-sample` | `libtauri_plugin_sample.so` | `"tauri_plugin_sample"` |
|
||||
| `my-awesome-plugin` | `libmy_awesome_plugin.so` | `"my_awesome_plugin"` |
|
||||
| `plugin_name` | `libplugin_name.so` | `"plugin_name"` |
|
||||
|
||||
---
|
||||
|
||||
## Files to Update in tauri-docs Repository
|
||||
|
||||
This content should be updated in the `tauri-apps/tauri-docs` repository, specifically in the file that generates the "Calling Rust From Mobile Plugins" section at https://tauri.app/develop/plugins/develop-mobile/#android-1.
|
||||
|
||||
The exact file path will be in the docs repository, likely something like:
|
||||
- `src/content/docs/develop/plugins/develop-mobile.mdx` or similar
|
||||
|
||||
## Benefits of This Change
|
||||
|
||||
1. **Clear naming convention**: Developers understand how the library name is derived
|
||||
2. **Portable code**: Using a constant makes it easy to update in one place
|
||||
3. **Better error messages**: The example includes helpful logging
|
||||
4. **Quick reference table**: Easy lookup for common patterns
|
||||
5. **Real-world example**: Shows actual plugin code structure
|
||||
Loading…
Reference in New Issue
Block a user