espresso3389 / pdfrx

pdfrx is yet another PDF viewer implementation that built on the top of pdfium. The plugin currently supports Android, iOS, Windows, macOS, Linux, and Web.
MIT License
60 stars 36 forks source link

Invalid Argument: Failed to load dynamic library pdfrx.framework on iOS #117

Closed ugochirico closed 4 weeks ago

ugochirico commented 1 month ago

I'm using pdfrx 1.0.51. I loaded the PdfViewer from a Uint8List in this way:

pdfrx.PdfViewer.data(
                        _pdfData!,
                        controller: _controller,
                       sourceName: filename
...

It works on Android and Web but on iOS I got this error: Failed to load dynamic library 'pdfrx.framework/pdfrx': dlopen(pdfrx.framework/pdfrx, 0x0001... The error appears inside the PdfViewer as in the attached screenshot msg6396260810-2707

ugochirico commented 1 month ago

The exception seems due to pdfium. The stack trace of the exception is: 0 _open (dart:ffi-patch/ffi_dynamic_library_patch.dart:11:43) 1 new DynamicLibrary.open (dart:ffi-patch/ffi_dynamic_library_patch.dart:22:12) 2 pdfium (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:32:43) 3 pdfium (package:pdfrx/src/pdfium/pdfrx_pdfium.dart) 4 _init. (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:47:7) 5 using (package:ffi/src/arena.dart:124:31) 6 _init (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:39:3) 7 PdfDocumentFactoryImpl.openCustom (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:164:5) 8 PdfDocumentFactoryImpl._openData (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:133:12) 9 PdfDocumentFactoryImpl.openData (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:92:7) 10 PdfDocument.openData (package:pdfrx/src/pdf_api.dart:172:35)

  1. PdfDocumentRefData.loadDocument (package:pdfrx/src/pdf_document_ref.dart:229:19)
espresso3389 commented 1 month ago

What iPhone (or Simulator) are you using? And, please show me your flutter doctor -v result.

ugochirico commented 1 month ago

I'm using iPhone 12 pro with iOS 16.5 This is the result of flutter doctor -v:

ugochirico@Air-di-Ugo flutter_instasign_sdk % flutter doctor -v
[!] Flutter (Channel stable, 3.19.5, on macOS 14.0 23A344 darwin-arm64, locale it-IT)
    • Flutter version 3.19.5 on channel stable at /Users/ugochirico/flutter
    ! Warning: `dart` on your path resolves to /usr/local/Cellar/dart/3.3.3/libexec/bin/dart, which is not inside your current Flutter SDK checkout at
      /Users/ugochirico/flutter. Consider adding /Users/ugochirico/flutter/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 300451adae (11 days ago), 2024-03-27 21:54:07 -0500
    • Engine revision e76c956498
    • Dart version 3.3.3
    • DevTools version 2.31.1
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[!] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    • Android SDK at /Users/ugochirico/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 15.3)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15E204a
    • CocoaPods version 1.15.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7772763)

[✓] VS Code (version 1.88.0)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (3 available)
    • iPhone 12 Pro di Ugo (mobile) • 00008101-0011104E3E82001E • ios            • iOS 16.5 20F66
    • macOS (desktop)               • macos                     • darwin-arm64   • macOS 14.0 23A344 darwin-arm64
    • Chrome (web)                  • chrome                    • web-javascript • Google Chrome 123.0.6312.107

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.
ugochirico commented 1 month ago

I'm trying to understand what is the issue. I tried your example and it works like a charm. So, I opened the products "Runner" from your example and from my app and I see that in your example, in the "Framework" folder I see pdfrx.framework, while in my app, I cannt see pdfrx.framework in the same folder (see attached screenshot). So it seems as in my app, the pdfrx.framework is not copied in the Runner.app. Why?

Screenshot 2024-04-07 alle 23 13 07 Screenshot 2024-04-07 alle 23 13 58
ugochirico commented 1 month ago

I found the issue!

To make pdfrx working, in the pod file we should add use_frameworks!

target 'Runner' do
  use_frameworks!
  use_modular_headers!

But, in my app, I have a pod that must be linked statically so I have to set use_framwork :linkage => :static With this setting pdfrx doesn't work anymore because you use dlopen with the path to the framework, that doesn't exist in the app because of linkage => static

On the other hand, if I remove linkage => static I have an issue during pod install:

[!] The 'Pods-Runner' target has transitive dependencies that include statically linked binaries: (GoogleUtilitiesComponents)

you can find something interesting to fix the issue in pdfrx here: https://github.com/dart-lang/sdk/issues/44328

ugochirico commented 1 month ago

I confirm. I tried in this way and it worked: In podfile I wrote:

target 'Runner' do
  use_frameworks! :linkage => :static
  use_modular_headers!

so that the other dependencies that require static linking worked, and in pdfrx_pdfium.dart, line 31-32 I wrote:

final pdfium =
    pdfium_bindings.pdfium(DynamicLibrary.process());

so that the symbols are loaded from the static linked library inside the process, and it worked.

Now we should find a way to manage both cases (dynamic or static linking) in your code.

espresso3389 commented 1 month ago

So, do you want me to introduce some mechanism to choose one of DynamicLibrary.process and DynamicLibrary.open?

espresso3389 commented 1 month ago

@ugochirico Could you please check PR #119? If it's feasible solution to your issue, I'll merge it to the master.

ugochirico commented 1 month ago

no. it doesn't work. It seems as it cannot find the symbols in the process.

0 DynamicLibrary.lookup (dart:ffi-patch/ffi_dynamic_library_patch.dart:33:70) 1 pdfium._FPDF_InitLibraryWithConfigPtr (package:pdfrx/src/pdfium/pdfium_bindings.dart:33:80) 2 pdfium._FPDF_InitLibraryWithConfigPtr (package:pdfrx/src/pdfium/pdfium_bindings.dart) 3 pdfium._FPDF_InitLibraryWithConfig (package:pdfrx/src/pdfium/pdfium_bindings.dart:35:44) 4 pdfium._FPDF_InitLibraryWithConfig (package:pdfrx/src/pdfium/pdfium_bindings.dart) 5 pdfium.FPDF_InitLibraryWithConfig (package:pdfrx/src/pdfium/pdfium_bindings.dart:26:12) 6 _init. (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:48:14) 7 using (package:ffi/src/arena.dart:124:31) 8 _init (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:40:3)

espresso3389 commented 1 month ago

@ugochirico

You told me that the following code worked:

final pdfium = pdfium_bindings.pdfium(DynamicLibrary.process());

So what do you expect me to do?

ugochirico commented 1 month ago

Yes, it worked when I changed it in the version ^1.0.51. I don't know why now it doesn't work with this new branch.

Anyway, I tried with a different approach by changing the podfile to specify that pdfrx must be loaded dynamically as a framework and I was able to make it working, without any change in pdfrx.

This is my updated podfile that works:

target 'Runner' do
  use_frameworks! :linkage => :static
  use_modular_headers!

  pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name == 'pdfrx'
        def pod.build_type;
          Pod::BuildType.new(:linkage => :dynamic, :packaging => :framework)
        end
      end
    end
  end

  pre_install do |installer|
      Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  end

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end
espresso3389 commented 1 month ago

@ugochirico So, can I close the issue? For later reference, I'll document it somewhere in README or such.

ugochirico commented 1 month ago

It's very strange. On my Mac, adding that lines in podfile it works. My colleague pull our app on his mac, with the same podfile and it doesn't work anymore. Same error as before. I'm trying to understand what exaclty is happening.

Did you try to set use_frameworks! :linkage => :static on your example?

ugochirico commented 1 month ago

Finally we was able to find the correct solution. The podfile must be configured in this way:

target 'Runner' do
  use_frameworks! :linkage => :static
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
end

pre_install do |installer|
  Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
  installer.pod_targets.each do |pod|
    if pod.name == 'pdfrx'
      def pod.build_type;
        Pod::BuildType.new(:linkage => :dynamic, :packaging => :framework)
      end
    end
  end
end