react-native-nordic-dfu: iOS build fails with "Use of undeclared identifier 'RNNordicDfu'" error

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

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 3
  • Comments: 21

Most upvoted comments

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:

  • replace the @import with #import <iOSDFULibrary/iOSDFULibrary-Swift.h> in RNNordicDfu.h. Patch below
  • add use_frameworks! to your Podfile

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>

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"]
  ]

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

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;

@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!

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.