This is a very specific question, but I don't know where to search anymore.
I am a Flutter developer and want to print plastic cards with an evolis Primecy 2 printer. Evlois does provide an SDK for android in the form of .so files. .html .html
I added the files to the correct folders in my android directory and generated the dart binding class via ffigen. So I can access the SDK. It also works for the function 'evolis_version'. That gives me the version 9.0.2.6484.
But when I try to call evolis_open() as the first link suggests, the app crashes. I do not catch an exception, it just crashes. I can look up the function, so it does exist.
The crash logs:
F/libc (22120): Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 22155 (1.ui), pid 22120 (systems.test_app)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'SUNMI/V3_MIX_EDLA_GL/V3_MIX:13/TKQ1.230110.001/40:user/release-keys'
Revision: '0'
ABI: 'arm64'
Timestamp: 2025-02-19 14:58:37.674946211+0100
Process uptime: 36s
Cmdline: deanisation.test_app
pid: 22120, tid: 22155, name: 1.ui >>> deanisation.test_app <<<
uid: 10158
tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
Cause: null pointer dereference
x0 0000000000000000 x1 0000006e536adaf8 x2 0000006e536adaf8 x3 0000000000000010
x4 0000000000000000 x5 0000cd860000ce6a x6 0000cd860000ce6a x7 0000cd680000cde6
x8 f546e016fd83d64d x9 f546e016fd83d64d x10 000000000000568b x11 0000006e7b9ff8d0
x12 000000002acdb8f0 x13 0000000000000000 x14 00000000ffffffee x15 0000000000000000
x16 0000000000004000 x17 0000000000000000 x18 0000006e7b49a000 x19 0000006e52bd9e75
x20 0000006e52bd83be x21 0000006e52bd4116 x22 0000000000000000 x23 0000006e7ba01000
x24 0000006e536ad000 x25 0000006e7b9ff788 x26 b400006f2acdb8d0 x27 0000006e7b9ff8c8
x28 0000006e7b9ff760 x29 0000006e7b9ff3d0
lr 0000006e52efe80c sp 0000006e7b9ff3b0 pc 0000006e52efe80c pst 0000000060000000
backtrace:
#00 pc 00000000004df80c /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (_jobject* evolis::JniUtils::getStaticField<_jobject*>(char const*, char const*, char const*)+124) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#01 pc 00000000004de33c /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::AndroidUtils::forEachUsbDevice(std::__ndk1::function<void (_jobject*)> const&)+72) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#02 pc 00000000004dca98 /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::AndroidUsbDeviceEnumerator::enumerate() const+72) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#03 pc 0000000000356598 /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::DeviceFinder::findOne(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, evolis::DeviceEnumerator*)+76) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#04 pc 0000000000356454 /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::DeviceFinder::findOne(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&)+184) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#05 pc 000000000033986c /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::Connection::build(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, evolis_open_mode_e)+176) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#06 pc 000000000032eae0 /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis::Context::open(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&, evolis_open_mode_e)+40) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#07 pc 0000000000325c14 /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis_open_with_mode+316) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#08 pc 0000000000325a9c /data/app/~~ATq07aqcr-JzX4yJnAR9lA==/deanisation.test_app-E6AIbCnKYHRpd1L8A3nZeA==/base.apk!libevolis.so (evolis_open+152) (BuildId: dc922624b7361818e45e46a577d9045ca4b9bc3b)
#09 pc 0000000000008264 [anon:dart-code]
Lost connection to device.
the Dart compiler exited unexpectedly.
The APK does contain the .so files, so that should not be a problem.
At this point, I don't know what else can I test. Is someone here who knows how to access this SDK?
% flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.27.2, on macOS 15.1.1 24B91 darwin-arm64, locale de-DE)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.1)
[!] Xcode - develop for iOS and macOS (Xcode 16.1)
✗ Unable to get list of installed Simulator runtimes.
✗ CocoaPods not installed.
CocoaPods is a package manager for iOS or macOS platform code.
Without CocoaPods, plugins will not work on iOS or macOS.
For more info, see /to/platform-plugins
For installation instructions, see .html#installation
[✓] Chrome - develop for the web
[✓] Android Studio (version 2024.1)
[✓] IntelliJ IDEA Ultimate Edition (version 2024.1.7)
[✓] VS Code (version 1.97.2)
[✓] Connected device (4 available)
[✓] Network resources
Here is how I call the function:
import 'dart:ffi' as ffi;
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:pos_app/ffi_libs/generated_evolis_bindings.dart';
import 'package:pos_app/utility/widgets/space.dart';
class EvoilsTestPage extends StatefulWidget {
const EvoilsTestPage({super.key});
@override
State<EvoilsTestPage> createState() => _EvoilsTestPageState();
}
class _EvoilsTestPageState extends State<EvoilsTestPage> {
late final EvolisBindings evoBinding;
String status = 'ready';
@override
void initState() {
if (!kIsWeb) {
final dynamicLibrary = Platform.isAndroid
? ffi.DynamicLibrary.open('libevolis.so')
: ffi.DynamicLibrary.process();
evoBinding = EvolisBindings(dynamicLibrary);
}
super.initState();
}
updateStatus(String status) {
print(status);
setState(() {
this.status = status;
});
}
_getEvoVersion() {
try {
final versionPtr = evoBinding.evolis_version();
String version = versionPtr.cast<Utf8>().toDartString();
updateStatus("evo version: $version");
} catch (e) {
updateStatus("evolis_version function NOT found: $e");
}
}
_lookUpFunction() {
String functionName = "evolis_open";
try {
updateStatus("start Print");
updateStatus("openPrinter");
final openFunc = evoBinding.lookup("evolis_open");
updateStatus('$functionName: ${openFunc.toString()}');
return;
} catch (e) {
updateStatus('$functionName does not seem to exist:\n\n${e.toString()}');
}
}
_testPrint() async {
ffi.Pointer<ffi.Char> namePtr = ffi.nullptr;
try {
String dartString = 'Evolis Primacy 2';
namePtr = dartString.toNativeUtf8().cast<ffi.Char>();
final printerPtr = evoBinding.evolis_open(namePtr);
if (printerPtr.address == 0) {
updateStatus("Failed to open printer.");
} else {
updateStatus(
"Printer opened successfully. ${printerPtr.toString()}");
}
print("closePrinter");
evoBinding.evolis_close(printerPtr);
print("free pointer");
malloc.free(namePtr);
} catch (e) {
malloc.free(namePtr);
updateStatus(e.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Evolis Printer Test")),
body: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(status),
Space.p40(),
ElevatedButton(
onPressed: () => _testPrint(),
child: Text("Test Print"),
),
ElevatedButton(
onPressed: _getEvoVersion,
child: Text("Evo Version"),
),
ElevatedButton(
onPressed: _lookUpFunction,
child: Text("Lookup Function"),
),
],
),
),
);
}
}
I wont throw the generated class in here because it is 14495 lines. But here is the important functions call
import 'dart:ffi' as ffi;
class EvolisBindings {
/// Holds the symbol lookup function.
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
lookup;
/// The symbols are looked up in [dynamicLibrary].
EvolisBindings(ffi.DynamicLibrary dynamicLibrary)
: lookup = dynamicLibrary.lookup;
/// The symbols are looked up with [lookup].
EvolisBindings.fromLookup(
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
lookup)
: lookup = lookup;
/// Connect to the printer referenced by the `name` argument.
/// Same as evolis_open_with_mode(a, EVOLIS_OM_AUTO)
ffi.Pointer<evolis_t> evolis_open(
ffi.Pointer<ffi.Char> name,
) {
return _evolis_open(
name,
);
}
late final _evolis_openPtr = lookup<
ffi.NativeFunction<
ffi.Pointer<evolis_t> Function(
ffi.Pointer<ffi.Char>)>>('evolis_open');
late final _evolis_open = _evolis_openPtr
.asFunction<ffi.Pointer<evolis_t> Function(ffi.Pointer<ffi.Char>)>();
/// Get library version at runtime.
ffi.Pointer<ffi.Char> evolis_version() {
return _evolis_version();
}
late final _evolis_versionPtr =
lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
'evolis_version');
late final _evolis_version =
_evolis_versionPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
}