Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS build fails with "Use of undeclared identifier 'RNNordicDfu'" error #171

Open
mtsap opened this issue Jul 29, 2022 · 21 comments
Open

iOS build fails with "Use of undeclared identifier 'RNNordicDfu'" error #171

mtsap opened this issue Jul 29, 2022 · 21 comments

Comments

@mtsap
Copy link

mtsap commented Jul 29, 2022

Tried it with this repo as well the one mentioned in the Readme.

Also tried adding the following line to the Podfile
pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu"
with no success.

Screenshot 2022-07-29 at 14 35 33

npx react-native info output:

System: OS: macOS 12.4 CPU: (4) x64 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz Memory: 29.89 MB / 8.00 GB Shell: 5.9 - /usr/local/bin/zsh Binaries: Node: 12.19.0 - ~/.nvm/versions/node/v12.19.0/bin/node Yarn: 1.22.19 - /usr/local/bin/yarn npm: 6.14.15 - ~/node-projects/arion2-app/node_modules/.bin/npm Watchman: 2022.06.13.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.2 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 21.4, iOS 15.5, macOS 12.3, tvOS 15.4, watchOS 8.5 Android SDK: Android NDK: 22.1.7171670 IDEs: Android Studio: 4.2 AI-202.7660.26.42.7486908 Xcode: 13.4.1/13F100 - /usr/bin/xcodebuild Languages: Java: 10.0.2 - /usr/bin/javac npmPackages: @react-native-community/cli: Not Found react: 17.0.1 => 17.0.1 react-native: 0.64.3 => 0.64.3 react-native-macos: Not Found npmGlobalPackages: *react-native*: Not Found

@Tale-Dev
Copy link

Tale-Dev commented Aug 4, 2022

@mtsap it's properly because of node version, you can try node v14.16.1

@samuel-gallet
Copy link

Does not build either with node v14.16.1 @Tale-Dev

@Tale-Dev
Copy link

@samuel-gallet thanks, are there any problem with node v14.16.1?

@mtsap
Copy link
Author

mtsap commented Aug 12, 2022

@samuel-gallet @Tale-Dev for me it buit. It was my mistake. I put the imports below this line:
#ifdef FB_SONARKIT_ENABLED

Moved them above and now it works.

@samuel-gallet
Copy link

I made the same mistake too @mtsap .

However I could not make it build because of a "modules are disabled" error.
I get Use of '@import' when C++ modules are disabled, consider using -fmodules and -fcxx-modules error in the RNNordicDfy.h file

Screenshot 2022-08-12 at 12 24 55

@CptFabulouso
Copy link

CptFabulouso commented Nov 28, 2022

Solution 1)
I solved it by adding the -fcxx-modules to Other C++ Flags (in Build Settings) with RN 0.70.6. I couldn't make it work after manually upgrading from RN 0.66.1, there was some different error, I had to first create a new clean RN project, copy content of ios folder to my project and fix changes in app icons, font resources etc. But that was just my case. Note that I think you can't use the new RN architecture with -fcxx-modules flag.

Solution 2)
To make it work without that flag the solution is following:

Patch

diff --git a/node_modules/react-native-nordic-dfu/ios/RNNordicDfu.h b/node_modules/react-native-nordic-dfu/ios/RNNordicDfu.h
index 619a95b..8632a49 100644
--- a/node_modules/react-native-nordic-dfu/ios/RNNordicDfu.h
+++ b/node_modules/react-native-nordic-dfu/ios/RNNordicDfu.h
@@ -1,7 +1,7 @@
 #import <CoreBluetooth/CoreBluetooth.h>
 #import <React/RCTBridgeModule.h>
 #import <React/RCTEventEmitter.h>
-@import iOSDFULibrary;
+#import <iOSDFULibrary/iOSDFULibrary-Swift.h>
 
 @interface RNNordicDfu : RCTEventEmitter<RCTBridgeModule, DFUServiceDelegate, DFUProgressDelegate, LoggerDelegate>

@manualexSP
Copy link

Hi @CptFabulouso thank you for the explanation of the import problem. I will add a fix to this fork and I will update the readme.

@CptFabulouso
Copy link

Ok. Btw I now think the second solution should also work with Flipper. I managed to make work Flipper with newest react-native-firebase, which also needs to use use_frameworks.

My solution was to add following to Podfile:

# items in array are for Firebase and should be changed to include the DFU lib, not sure how exactly ATM.
static_frameworks = ['Firebase','FirebaseCoreInternal', 'FirebaseCoreExtension', 'FirebaseInstallations', 'FirebaseCore', 'FirebaseMessaging', 'GoogleUtilities']  
pre_install do |installer|
  installer.pod_targets.each do |pod|
    if static_frameworks.include?(pod.name)
      puts "Overriding the static_frameworks? method for #{pod.name}"
      def pod.build_type;
        Pod::BuildType.new(:linkage => :static, :packaging => :framework)
      end
    end
  end
end

target 'YourApp' do
    ...
end

And if that does not work, someone found another approach described here.
So if you can take the time to find out some of these approaches work, you may also mention that in the readme.

@ervibern
Copy link

ervibern commented Jul 4, 2023

This is really promising. Currently struggling to get it to build for an Expo app. I used @manualexSP fork with the readme instructions but it didn't build. If anyone could help, would really appreciate it. If I don't want to lose Flipper functionality, should I try static_frameworks = ['react-native-nordic-dfu'] as per @CptFabulouso suggestion?

Podfile

target 'MyApp' do
  use_expo_modules!
  config = use_native_modules!
  
  // added those 2 lines
  pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu"
  use_frameworks! :linkage => :static

  use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks']

  # Flags change depending on the env values.
  flags = get_default_flags()

  use_react_native!(
    :path => config[:reactNativePath],
# @generated begin expo-community-flipper-isprod - expo prebuild (DO NOT MODIFY) sync-828c22a1a38236bf5b7c203393f474bc68356b34
    # ENV value added to support Hermes
    :production => ENV["PRODUCTION"] == "1" ? true : false,
# @generated end expo-community-flipper-isprod
    :hermes_enabled => podfile_properties['expo.jsEngine'] == 'hermes',
    :fabric_enabled => flags[:fabric_enabled],
# @generated begin expo-community-flipper-urn - expo prebuild (DO NOT MODIFY) sync-c7cb57ad0548737963234cf3378d4b0e06dca78b
    :flipper_configuration => FlipperConfiguration.enabled(["Debug", "Release"]),
# @generated end expo-community-flipper-urn
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/..",
    #
    # Uncomment to opt-in to using Flipper
    # Note that if you have use_frameworks! enabled, Flipper will not work
    # :flipper_configuration => !ENV['CI'] ? FlipperConfiguration.enabled : FlipperConfiguration.disabled,
  )

  post_install do |installer|
    react_native_post_install(
      installer,
      # Set `mac_catalyst_enabled` to `true` in order to apply patches
      # necessary for Mac Catalyst builds
      :mac_catalyst_enabled => false
    )
    __apply_Xcode_12_5_M1_post_install_workaround(installer)

    # This is necessary for Xcode 14, because it signs resource bundles by default
    # when building for devices.
    installer.target_installation_results.pod_target_installation_results
      .each do |pod_name, target_installation_result|
      target_installation_result.resource_bundle_targets.each do |resource_bundle_target|
        resource_bundle_target.build_configurations.each do |config|
          config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
        end
      end
    end
  end

  post_integrate do |installer|
    begin
      expo_patch_react_imports!(installer)
    rescue => e
      Pod::UI.warn e
    end
  end
end

AppDelegate.mm

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  RCTAppSetupPrepareApp(application);

  RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];

#if RCT_NEW_ARCH_ENABLED
  _contextContainer = std::make_shared<facebook::react::ContextContainer const>();
  _reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
  _contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
  _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
  bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif

  NSDictionary *initProps = [self prepareInitialProps];
  UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:initProps];

  rootView.backgroundColor = [UIColor whiteColor];
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  UIViewController *rootViewController = [self.reactDelegate createRootViewController];
  rootViewController.view = rootView;
  self.window.rootViewController = rootViewController;
  [self.window makeKeyAndVisible];

  [super application:application didFinishLaunchingWithOptions:launchOptions];
  
  // Added those 3 blocks
  [RNNordicDfu setCentralManagerGetter:^() {
        return [[CBCentralManager alloc] initWithDelegate:nil 
        queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
   }];

  [RNNordicDfu setOnDFUComplete:^() {
        NSLog(@"onDFUComplete");
   }];
    
  [RNNordicDfu setOnDFUError:^() {
        NSLog(@"onDFUError");
   }];

  return YES;
}

@manualexSP
Copy link

@ervibern I will give it a try to the @CptFabulouso mention and I will come back this week to you guys.

@manualexSP
Copy link

Ok so I tested on a react-native 0.71.8 project, the pre_install logic with FlipperConfiguration.enabled and it works.

  static_frameworks = ['iOSDFULibrary']  
  pre_install do |installer|
    installer.pod_targets.each do |pod|
      if static_frameworks.include?(pod.name)
        puts "Overriding the static_frameworks? method for #{pod.name}"
        def pod.build_type;
          Pod::BuildType.new(:linkage => :static, :packaging => :framework)
        end
      end
    end
  end

I updated the README and I put two solutions one with FlipperConfiguration.disabled and one with FlipperConfiguration.enabled. check here

I also added a new section with Issues and I put a link from this conversation in case others have problems too.

@ervibern give it a try now and let us know how it works. Also, I never tested this library with Expo and I never worked with it, so I'm not sure how things are going to work for you.

@ervibern
Copy link

@manualexSP Can confirm that your current fork builds and works on my app with react native 0.70.8 and expo 47.0.14! :) Flipper is enabled and works together with DFU package. I have to figure out how to add those custom modifications to Podfile and AppDelegate.mm to the Expo project but this is a separate topic. Thanks for your work!

@eddyv19
Copy link

eddyv19 commented Oct 2, 2023

@ervibern Hi, i am also struggling to make DFU work in an expo project (49.0.0). Have you figured out how to incorporate those modifications to Podfile and AppDelegate.mm? Very much stuck with this and i really hope you can help :)

@ervibern
Copy link

ervibern commented Oct 11, 2023

Hi @eddyv19 - sorry for the late response but here is how I made it work for my use case. Hope it helps!

First, you need to add the following modifications to AppDelegate.mm file.

// AppDelegate.mm

#import "RNNordicDfu.h"

<...>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
 
<...>

  // Insert the modifications here
  [RNNordicDfu setCentralManagerGetter:^() {
    return [[CBCentralManager alloc] initWithDelegate:nil queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];
  }];

  [RNNordicDfu setOnDFUComplete:^() {
    NSLog(@"onDFUComplete");
  }];

  [RNNordicDfu setOnDFUError:^() {
    NSLog(@"onDFUError");
  }];
  // End of modifications

  [super application:application didFinishLaunchingWithOptions:launchOptions];

  return YES;

<...>

}

Then you need to modify the Podfile.

// Podfile

<...>

target '<YourAppName>' do

  static_frameworks = ['iOSDFULibrary']
  
  pre_install do |installer|
    installer.pod_targets.each do |pod|
      if static_frameworks.include?(pod.name)
        puts "Overriding the static_frameworks? method for #{pod.name}"
        def pod.build_type;
          Pod::BuildType.new(:linkage => :static, :packaging => :framework)
        end
      end
    end
  end

  pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu"

  use_expo_modules!
  config = use_native_modules!

<...>

With those modifications the app built fine and I was able to use DFU functionality.

However, if you are using Expo Managed workflow and want to generate the native files during the build process, you need to write a custom plugin that writes the modification during build time. The custom plugin needs to be added to your Expo app configuration file app.json (or app.config.js).

// app.config.js

    "plugins": [
      "@config-plugins/react-native-ble-plx",
      "./plugin/nordic-dfu/index.js",

Here is the custom plugin file that I added in plugin/nordic-dfu folder (name is arbitrary).

// plugin/nordic-dfu/index.js

const { withDangerousMod, withPlugins, withAppDelegate } = require('@expo/config-plugins');
const { readFileSync, writeFileSync } = require('fs');
const { resolve } = require('path');

function withNordicDfuPod(config) {
  return withDangerousMod(config, [
    'ios',
    (cfg) => {
      const { platformProjectRoot } = cfg.modRequest;
      const podfile = resolve(platformProjectRoot, 'Podfile');
      const contents = readFileSync(podfile, 'utf-8');
      const lines = contents.split('\n');
      const index = lines.findIndex((line) => /\s+use_expo_modules!/.test(line));

      // Add the custom lines above the use_expo_modules line
      const customLines = [
        "  static_frameworks = ['iOSDFULibrary']",
        '',
        '  pre_install do |installer|',
        '    installer.pod_targets.each do |pod|',
        '      if static_frameworks.include?(pod.name)',
        '        puts "Overriding the static_frameworks? method for #{pod.name}"',
        '        def pod.build_type;',
        '          Pod::BuildType.new(:linkage => :static, :packaging => :framework)',
        '        end',
        '      end',
        '    end',
        '  end',
        '',
        '  pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu"',
      ];

      writeFileSync(
        podfile,
        [...lines.slice(0, index), ...customLines, ...lines.slice(index)].join('\n')
      );

      return cfg;
    },
  ]);
}

function withNordicDfuAppDelegate(config) {
  return withAppDelegate(config, (cfg) => {
    const { modResults } = cfg;
    const { contents } = modResults;
    const lines = contents.split('\n');

    const importIndex = lines.findIndex((line) => /^#import "AppDelegate.h"/.test(line));
    const didLaunchIndex = lines.findIndex((line) =>
      /\[super application:application didFinishLaunching/.test(line)
    );

    // Additional lines to add
    const additionalLines = [
      '  // Insert the modifications here',
      '  [RNNordicDfu setCentralManagerGetter:^() {',
      '    return [[CBCentralManager alloc] initWithDelegate:nil queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)];',
      '  }];',
      '',
      '  [RNNordicDfu setOnDFUComplete:^() {',
      '    NSLog(@"onDFUComplete");',
      '  }];',
      '',
      '  [RNNordicDfu setOnDFUError:^() {',
      '    NSLog(@"onDFUError");',
      '  }];',
      '  // End of modifications',
    ];

    modResults.contents = [
      ...lines.slice(0, importIndex + 1),
      '#import "RNNordicDfu.h"',
      ...lines.slice(importIndex + 1, didLaunchIndex),
      ...additionalLines,
      lines[didLaunchIndex], // Preserve the existing line
      ...lines.slice(didLaunchIndex + 1),
    ].join('\n');

    return cfg;
  });
}

function withNordicDfuPodfile(config) {
  return withPlugins(config, [withNordicDfuPod, withNordicDfuAppDelegate]);
}

module.exports = withNordicDfuPodfile;

@eddyv19
Copy link

eddyv19 commented Oct 13, 2023

Hi @ervibern. Thanks very much for the elaborate reply. I really appreciate it.! I have not had a chance to try it but will do so today.

@niclaslindberg
Copy link

Hi @ervibern Wonderful! Even with the plugin defined! Completely wonderful. More people like you in the world! Thank you! :) Will try it out ASAP!

@niclaslindberg
Copy link

Once again. Thanks @ervibern. Tested it out and it builds nice in Expo. Small typo above:

"plugins": [
    ["@config-plugins/react-native-ble-plx"],
    ["./plugin/nordic-dfu/index.js"]
  ]

@AshlandWest
Copy link

This seems potentially related to an issue I am experiencing on ios build.
Screenshot 2023-10-26 at 6 53 37 PM

Is this related, or should I start a new thread?

@CptFabulouso
Copy link

I think it is related, solutions above do not work?

@dev-simpleplan
Copy link

This seems potentially related to an issue I am experiencing on ios build. Screenshot 2023-10-26 at 6 53 37 PM

Is this related, or should I start a new thread?

I am facing the same issue, have you got any solution?

@AshlandWest
Copy link

I do not, but this is outside my area of experience, so I'm probably doing something completely wrong.
The import change was already done, I think thanks to @manualexSP since I'm using his fork.

I tried disabling flipper and adding the import line, but now RTCBridge is breaking, before it gets to the IOSDFU import.

target '<MyAppName>' do
  config = use_native_modules!

  # React Native Nordic DFU Setup
  pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu"
 # I added this line since my first comment 
  use_frameworks! :linkage => :static
  
  # Flags change depending on the env values.
  flags = get_default_flags()

  use_react_native!(
    :path => config[:reactNativePath],
    # Hermes is now enabled by default. Disable by setting this flag to false.
    :hermes_enabled => flags[:hermes_enabled],
    :fabric_enabled => flags[:fabric_enabled],
    # Enables Flipper.
    #
    # Note that if you have use_frameworks! enabled, Flipper will not work and
    # you should disable the next line.
    # :flipper_configuration => flipper_config,
    :flipper_configuration => FlipperConfiguration.disabled,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

Screenshot 2023-10-31 at 1 44 08 PM

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

No branches or pull requests

10 participants