【问题标题】:How to create a shared library in android and use it in flutter?如何在android中创建共享库并在flutter中使用?
【发布时间】:2022-10-15 04:41:10
【问题描述】:

TL;博士

我在meaning_of_life.c 中有这个 C 函数:

#define FFI_PLUGIN_EXPORT

FFI_PLUGIN_EXPORT int getMeaningOfLife(){
    return 42;
}

我尝试使用多种方法将其编译为共享库 (.so),但是当我尝试在 android 上使用它时,如incompatible targetfile in wrong format 时不断出现错误。你能告诉我正确的方法吗?

我尝试了什么:

  1. 创建上述C文件
  2. 创建一个flutter_ffi插件,它会像这样使用它(这在这里有点无关紧要):
    add_library(meaningoflife SHARED IMPORTED )
    set_target_properties(meaningoflife
            PROPERTIES
            IMPORTED_LOCATION
            /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so
            )
    
    target_link_libraries(my_plugin meaningoflife)
    
    1. 阅读alotalot... 的文档,并在此处进行了很多搜索,但大多数相关问题和答案都非常古老并且使用旧方法(他们不使用 cmake)
    2. 创建一个将使用该插件的 Flutter 应用
    3. 从插件创建一个.so共享库,首先我在this页面上尝试了该方法(使用NDK编译器和工具链):
    cd /home/haidar/dev_haidar/c++/meaning_of_life/Src
    comp=/home/haidar/Android/Sdk/ndk/25.1.8937393/toolchains/llvm/prebuilt/linux-x86_64/bin
    $comp/aarch64-linux-android26-clang  -fPIC meaning_of_life.c -o libLife.so -shared // also tried with other compilers as armv7a-linux-androideabi26-clang
    

    该库已生成,但是当我使用它时,出现上述错误之一(取决于用于创建它的编译器),例如,这是错误的一部分:

    [        ] FAILURE: Build failed with an exception.
    [        ] * What went wrong:
    [        ] Execution failed for task ':image_magick_ffi:buildCMakeDebug[armeabi-v7a]'.
    [        ] > Build command failed.
    [        ]   Error while executing process /home/haidar/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a image_magick_ffi}
    [        ]   ninja: Entering directory `/home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a'
    [        ]   [1/1] Linking C shared library /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
    [        ]   FAILED: /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so 
    [        ]   : && /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --gcc-toolchain=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security  -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libimage_magick_ffi.so -o /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so CMakeFiles/image_magick_ffi.dir/image_magick_ffi.c.o  /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so  -latomic -lm && :
    [        ]   /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so: incompatible target
    [        ]   clang: error: linker command failed with exit code 1 (use -v to see invocation)
    [        ]   ninja: build stopped: subcommand failed.
    [        ] * Try:
    [        ] > Run with --debug option to get more log output.
    [        ] > Run with --scan to get full insights.
    [        ] * Exception is:
    [        ] org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':image_magick_ffi:buildCMakeDebug[armeabi-v7a]'.
    [        ]  at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:147)
    [        ]  at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
    [        ]  at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:145)
    [        ]  at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
    [        ]  at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
    [        ]  at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    [        ]  at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
    [        ]  at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    [        ]  at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    [        ]  at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    [        ]  at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
    [        ]  at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    [        ]  at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    [        ]  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    [        ]  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    [        ]  at java.base/java.lang.Thread.run(Thread.java:829)
    [        ] Caused by: org.gradle.internal.UncheckedException: Build command failed.
    [        ] Error while executing process /home/haidar/Android/Sdk/cmake/3.18.1/bin/ninja with arguments {-C /home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a image_magick_ffi}
    [        ] ninja: Entering directory `/home/haidar/dev_haidar/flutter/image_magick_ffi/android/.cxx/Debug/b5x10294/armeabi-v7a'
    [        ] [1/1] Linking C shared library /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so
    [        ] FAILED: /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so 
    [        ] : && /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/bin/clang --target=armv7-none-linux-androideabi16 --gcc-toolchain=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64 --sysroot=/home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/sysroot -fPIC -g -DANDROID -fdata-sections -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -D_FORTIFY_SOURCE=2 -march=armv7-a -mthumb -Wformat -Werror=format-security  -O0 -fno-limit-debug-info  -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libgcc_real.a -Wl,--exclude-libs,libatomic.a -static-libstdc++ -Wl,--build-id -Wl,--fatal-warnings -Wl,--exclude-libs,libunwind.a -Wl,--no-undefined -Qunused-arguments -shared -Wl,-soname,libimage_magick_ffi.so -o /home/haidar/dev_haidar/flutter/magick_app/build/image_magick_ffi/intermediates/cxx/Debug/b5x10294/obj/armeabi-v7a/libimage_magick_ffi.so CMakeFiles/image_magick_ffi.dir/image_magick_ffi.c.o  /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so  -latomic -lm && :
    [        ] /home/haidar/Android/Sdk/ndk/21.1.6352462/toolchains/llvm/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld: error: /home/haidar/dev_haidar/c++/meaning_of_life/Src/libLife.so: incompatible target
    [        ] clang: error: linker command failed with exit code 1 (use -v to see invocation)
    [        ] ninja: build stopped: subcommand failed.
    [        ]  at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:68)
    [        ]  at org.gradle.internal.UncheckedException.throwAsUncheckedException(UncheckedException.java:41)
    [        ]  at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:107)
    [        ]  at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
    [        ]  at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
    [        ]  at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:242)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:227)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:210)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:193)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:171)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
    [        ]  at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
    [        ]  at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
    [        ]  at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
    [        ]  at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
    [        ]  at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
    [        ]  at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
    [        ]  at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
    [        ]  at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
    [        ]  at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
    [        ]  at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
    [        ]  at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:61)
    [        ]  at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:42)
    [        ]  at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
    [        ]  at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
    [        ]  at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:180)
    [        ]  at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:75)
    [        ]  at org.gradle.internal.Either$Right.fold(Either.java:175)
    [        ]  at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
    [        ]  at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:73)
    [        ]  at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:48)
    [        ]  at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
    [        ]  at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
    [        ]  at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
    [        ]  at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
    [        ]  at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
    [        ]  at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
    [        ]  at java.base/java.util.Optional.orElseGet(Optional.java:369)
    [        ]  at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
    [        ]  at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
    [        ]  at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
    [        ]  at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
    [        ]  at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
    [        ]  at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
    [        ]  at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
    [        ]  at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
    [        ]  at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:114)
    [        ]  at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
    [        ]  at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
    [        ]  at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
    [        ]  at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:249)
    [        ]  at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:86)
    [        ]  at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:54)
    [        ]  at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
    [        ]  at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
    [        ]  at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
    [        ]  at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
    [        ]  at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
    [        ]  at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
    [        ]  at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:287)
    [        ]  at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
    [        ]  at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
    [        ]  at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
    [        ]  at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
    [        ]  at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
    [        ]  at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
    [        ]  at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
    [        ]  at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:144)
    [        ]  at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:133)
    [        ]  at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
    [        ]  at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
    [        ]  at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
    [        ]  at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
    [        ]  at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
    [        ]  at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
    [        ]  at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
    [        ]  at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
    [        ]  at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:333)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:320)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:313)
    [        ]  at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:299)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:143)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:227)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:218)
    [        ]  at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:140)
    [        ]  at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    [        ]  at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    [        ]  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    [        ]  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    [        ]  at java.base/java.lang.Thread.run(Thread.java:829)
    [        ] Caused by: Build command failed.
    ...
    
    1. 从插件创建一个.so共享库,这次我尝试了official android docs page上的方法,我用这个生成了一个json文件的命令用另一个命令编译了上面的C文件,但是我没有了解在这种情况下如何创建共享库(命令模板来自同一页面):
    cmake -H/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_FIND_ROOT_PATH=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/haidar/Android/Sdk/ndk/25.1.8937393/build/cmake/android.toolchain.cmake -DANDROID_ABI=armeabi-v7a -DANDROID_NDK=/home/haidar/Android/Sdk/ndk/25.1.8937393 -DANDROID_PLATFORM=android-23 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a -DCMAKE_ANDROID_NDK=/home/haidar/Android/Sdk/ndk/25.1.8937393 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_RUNTIME_OUTPUT_DIRECTORY=/home/haidar/dev_haidar/c++/meaning_of_life -DCMAKE_MAKE_PROGRAM=/home/haidar/Android/Sdk/cmake/3.22.1/bin/ninja -DCMAKE_SYSTEM_NAME=Android -DCMAKE_SYSTEM_VERSION=26 -B/home/haidar/dev_haidar/c++/meaning_of_life -GNinja
    

    注意:我尝试运行flutter应用程序(使用插件,使用.so库)的设备是华为p10 lite,它的CPU支持arm63-v8a、armeabi-v7a、armeabi。

    列出解决此问题的步骤或提示将不胜感激。谢谢。

    更新

    我在 github 上找到了this shell script(这与我在上面的步骤 6 中所做的非常相似),我对其进行了调整以适应我的路径,它成功地为每个架构生成了 .so 文件。我创建了一个纯 android 应用程序并从应用程序中调用它,一切正常。

    add_library(getnumber SHARED IMPORTED)
    set_target_properties(getnumber PROPERTIES IMPORTED_LOCATION
            /home/haidar/dev_haidar/c++/getnumber/Src/prebuilt/release/arm64-v8a/libgetnumber.so
            )
    target_link_libraries(imagemagicknativeapp getnumber)
    

    一切正常。

    当我以完全相同的方式在颤振插件中依赖它时

    add_library(getnumber SHARED IMPORTED )
    set_target_properties(getnumber
            PROPERTIES
            IMPORTED_LOCATION
            /home/haidar/dev_haidar/flutter/image_magick_ffi/src/Dependencies/ImageMagick/lib/android/arm64-v8a/libgetnumber.so
            )
    
    target_link_libraries(image_magick_ffi getnumber)
    

    我仍然收到错误

    ld: error: /home/haidar/dev_haidar/flutter/image_magick_ffi/src/Dependencies/ImageMagick/lib/android/arm64-v8a/libgetnumber.so is incompatible with armelf_linux_eabi
    

    我知道问题与编译/链接目标有关 与实际目标(我的手机)不同,但我怎样才能告诉颤振改变这种行为?

【问题讨论】:

  • 从这个[和你之前/删除的(?)问题],你得到的错误表明如果构建了lib,它是为错误的架构构建的。无论是不是arm 和/或它是为 [松散] arm/linuxarm/standalone 而不是 arm/android 构建的。您必须找到 make 过程正在使用的库的完整路径。如有必要,您可以在 strace 下运行它,或者在 make 本身中打开一些详细信息。然后,如果您执行file /path/to/my.so,它会告诉您它是为哪个拱门而构建的。您必须确保这与 FFI 所期望的相同。
  • 请注意,您使用--debug 和/或--scan 重新运行的构建请求。那么,你做到了吗?
  • @CraigEstey我知道问题是构建库的目标架构错误,但问题是我做错了什么?另外,上面的日志是在我运行颤振应用程序时在 android studio 中使用 -v 标志构建的,我还能将你所说的这些标志放在哪里?
  • @CraigEstey 如果您查看更新的问题,您可以看到我正在正确生成 .so 文件,并且对于正确的架构,问题似乎出现在使用颤振插件的颤振应用程序或颤振插件本身
  • 如 cmets 在您之前的问题中所述,只需添加资源第三方开源代码,让 CMake 构建它。

标签: android c flutter dart-ffi


【解决方案1】:

感谢来自不和谐的 FlutterDev 的 Piero5W11,我能够解决这个特殊问题。

解决的办法是从CMake中删除与添加库相关的部分(不要从CMake中添加库,我们会从其他地方添加),所以删除这部分:

add_library(getnumber SHARED IMPORTED)
set_target_properties(getnumber PROPERTIES IMPORTED_LOCATION
        /home/haidar/dev_haidar/c++/getnumber/Src/prebuilt/release/arm64-v8a/libgetnumber.so
        )
target_link_libraries(imagemagicknativeapp getnumber)

来自CMakeLists.txt, 而是将共享库复制到{PLUGIN_PROJECT_ROOT}/android/src/main/jniLibs/{ABI_VERSION}/libgetnumber.so(替换通配符)

只需执行此操作并在 CMakeLists 或 gradle 文件中执行零其他配置。

至于 dart 方面,该库将与任何其他库一样与应用程序捆绑在一起,因此您可以使用 dart 动态加载器按其名称 getnumber 加载它,然后使用它在其中查找符号。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 2018-02-27
    相关资源
    最近更新 更多