Skip to content

Conversation

@DatL4g
Copy link

@DatL4g DatL4g commented Feb 15, 2025

Introduce a NativeLoader which takes care of loading native libraries. ReLinker is not needed on API Level > 23 and causes more trouble than it solves.

Refs: #341

Introduce a NativeLoader which takes care of loading native libraries.
ReLinker is not needed on API Level > 23 and causes more trouble than it solves.

Refs: rive-app#341
@ernestoyaquello
Copy link

Does this fix #341, or is it just related to it? I am not entirely sure what's going on here. 😅

@DatL4g
Copy link
Author

DatL4g commented Feb 17, 2025

@ernestoyaquello It's related to the mentioned issue since it's a known bug in ReLinker for years.
It will probably fix the issue as well, at least I don't see any reason why it should not work after merging.
I also use this kind of method in production apps and works without crashes, no matter if real/emulator or architecture.

More Context

Rive uses ReLinker to load native code which is only needed on older Android API Levels (below 23, Android Marshmallow).
It uses it's own native code loading process instead of System.loadLibrary because older phones did not support this properly.

Starting with Android 23 and up the System.loadLibrary works without issues.

Code Explanation

The updated and introduced code checks if the phone is old, then it uses ReLinker, otherwise it uses the normal System.loadLibrary method.
Additionally it won't crash the application if Rive could not be initialized, the Rive.init method returns a Boolean whether it could be loaded.
This way people can dynamically disable animations, only thing to mention is that it will always return false if it's called more than once.

Work Around while not merged

I use this code to initialize rive properly:
Btw I am using a more complex version of NativeLoader here which is not required for rive.

/**
 * Retrieves the rive native binary name using reflection, falls back to "rive-android"
 * Uses NativeLoader to load the native binary
 * Sets the default renderer using reflection
 */
fun Rive.initSafely(
    context: Context,
    defaultRenderer: RendererType = defaultRendererType
) {
    val riveClass = "app.rive.runtime.kotlin.core.Rive"
    val libName = runCatching {
        val clazz = Class.forName(riveClass)
        val field = clazz.getDeclaredField("RIVE_ANDROID")
        field.isAccessible = true
        field.get(null) as? String
    }.getOrNull()?.trim()?.ifBlank { null } ?: "rive-android"

    val libLoaded = NativeLoader.loadLibrary(context, libName)
    val rendererSet = this.defaultRendererType == defaultRenderer || runCatching {
        val clazz = Class.forName(riveClass)
        val field = clazz.getDeclaredField("defaultRendererType")
        field.isAccessible = true
        field.set(clazz, defaultRenderer)
    }.isSuccess

    if (libLoaded && rendererSet) {
        initializeCppEnvironment()
    } else {
        init(context, defaultRenderer)
    }
}

@umberto-sonnino
Copy link
Contributor

HI @DatL4g, thanks for your contribution!

It looks very promising and we're keen to find a way to resolve #341 for all those who reported it. As I mentioned in the issue thread, before integrating this PR, we'd like to test this and make sure this is solving the crashes.

Could you give us more specific repro steps? Which specific devices/ABIs have you confirmed experience the crash with the current implementation?

Once we validate this, we're happy to merge it

blakdragan7 and others added 4 commits March 5, 2025 04:37
Diffs=
f161bf4679 Tighter RHI integration, extra build options (#9149)
This lets the editor (and users of rive_native) draw text procedurally a little more easily directly through the runtime's RawText feature. This makes it easier to use all the high level features of our Text object in a procedural way, which is helpful for the editor to use on the Stage. Based on discussions with @alxgibsn where we found that there wasn't a good way to draw text with ellipses on the stage.

You could (and we did) previously do this by using helpers like DisplayText which would do all the styling and glyph rendering in Dart. This will be more performant for cases where you don't need control of each individual glyph from Dart and just want to draw a blob of styled text. It will incur much less FFI overhead and should be used by the editor when possible for text handles/helpers (Rive Text should still go through the usual path as modifiers need per glyph control, Raw/RenderText does not work with modifiers).

Diffs=
de0026bd59 Add RenderText to rive_native (#9146)
the actual crash was caused by using size_t instead of int for the index.
Since it would be set to -1 at the last loop, being a size_t would set it to max int and overflow causing a crash.
But for safety I decided to change when converters are deleted, following how file assets are stored and only deleted when the file is deleted.

Diffs=
df6ccaa5ff fix dat converter formula crash (#9168)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants