├── example ├── .watchmanconfig ├── .gitattributes ├── .babelrc ├── app.json ├── android │ ├── app │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ └── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── nordicdfuexample │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ │ └── AndroidManifest.xml │ │ ├── BUCK │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── keystores │ │ ├── debug.keystore.properties │ │ └── BUCK │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── .buckconfig ├── ios │ ├── NordicDFUExample.xcworkspace │ │ ├── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ │ └── contents.xcworkspacedata │ ├── NordicDFUExample │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── AppDelegate.m │ │ └── Base.lproj │ │ │ └── LaunchScreen.xib │ ├── Podfile │ ├── Podfile.lock │ └── NordicDFUExample.xcodeproj │ │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── NordicDFUExample.xcscheme │ │ └── project.pbxproj ├── __tests__ │ ├── index.ios.js │ └── index.android.js ├── index.ios.js ├── index.android.js ├── package.json ├── .gitignore ├── .flowconfig └── app.js ├── .gitattributes ├── android ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── pilloxa │ │ └── dfu │ │ ├── RNNordicDfuPackage.java │ │ ├── DfuService.java │ │ ├── NotificationActivity.java │ │ └── RNNordicDfuModule.java └── build.gradle ├── .gitignore ├── ios ├── RNNordicDfu.h ├── RNNordicDfu.xcodeproj │ └── project.pbxproj └── RNNordicDfu.m ├── .npmignore ├── react-native-nordic-dfu.podspec ├── index.d.ts ├── circle.yml ├── LICENSE ├── package.json ├── index.js └── README.md /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["module:metro-react-native-babel-preset"] 3 | } 4 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NordicDFUExample", 3 | "displayName": "NordicDFUExample" 4 | } -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | NordicDFUExample 3 | 4 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pilloxa/react-native-nordic-dfu/HEAD/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Nov 28 15:32:55 CET 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | 8 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jun 26 16:03:16 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/__tests__/index.ios.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.ios.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /example/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from "react"; 8 | import { AppRegistry } from "react-native"; 9 | 10 | import NordicDFUExample from "./app"; 11 | 12 | AppRegistry.registerComponent("NordicDFUExample", () => NordicDFUExample); 13 | -------------------------------------------------------------------------------- /example/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from "react"; 8 | import { AppRegistry } from "react-native"; 9 | 10 | import NordicDFUExample from "./app"; 11 | 12 | AppRegistry.registerComponent("NordicDFUExample", () => NordicDFUExample); 13 | -------------------------------------------------------------------------------- /example/__tests__/index.android.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import Index from '../index.android.js'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/nordicdfuexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.nordicdfuexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "NordicDFUExample"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NordicDFUExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "postinstall": "(cd ios && pod install)", 7 | "start": "node node_modules/react-native/local-cli/cli.js start", 8 | "test": "jest" 9 | }, 10 | "dependencies": { 11 | "react": "16.8.3", 12 | "react-native": "0.59.4", 13 | "react-native-ble-manager": "6.6.2", 14 | "react-native-nordic-dfu": "file:../", 15 | "rn-fetch-blob": "^0.10.12" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'NordicDFUExample' 2 | include ':react-native-fetch-blob' 3 | project(':react-native-fetch-blob').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fetch-blob/android') 4 | include ':react-native-nordic-dfu' 5 | project(':react-native-nordic-dfu').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-nordic-dfu/android') 6 | include ':react-native-ble-manager' 7 | project(':react-native-ble-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-ble-manager/android') 8 | 9 | include ':app' 10 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | 47 | # CocoaPods 48 | Pods/ -------------------------------------------------------------------------------- /ios/RNNordicDfu.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | @import iOSDFULibrary; 5 | 6 | @interface RNNordicDfu : RCTEventEmitter 7 | 8 | @property (strong, nonatomic) NSString * deviceAddress; 9 | @property (strong, nonatomic) RCTPromiseResolveBlock resolve; 10 | @property (strong, nonatomic) RCTPromiseRejectBlock reject; 11 | 12 | + (void)setCentralManagerGetter:(CBCentralManager * (^)())getter; 13 | + (void)setOnDFUComplete:(void (^)())onComplete; 14 | + (void)setOnDFUError:(void (^)())onError; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | 2 | # OSX 3 | # 4 | .DS_Store 5 | 6 | # node.js 7 | # 8 | node_modules/ 9 | npm-debug.log 10 | yarn-error.log 11 | 12 | 13 | # Xcode 14 | # 15 | build/ 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | xcuserdata 25 | *.xccheckout 26 | *.moved-aside 27 | DerivedData 28 | *.hmap 29 | *.ipa 30 | *.xcuserstate 31 | project.xcworkspace 32 | 33 | 34 | # Android/IntelliJ 35 | # 36 | build/ 37 | .idea 38 | .gradle 39 | local.properties 40 | *.iml 41 | 42 | # BUCK 43 | buck-out/ 44 | \.buckd/ 45 | *.keystore 46 | 47 | 48 | # Example dir 49 | example 50 | -------------------------------------------------------------------------------- /react-native-nordic-dfu.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "react-native-nordic-dfu" 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | 10 | s.authors = { "Pilloxa" => "recruitment@pilloxa.com" } 11 | s.homepage = "https://github.com/Pilloxa/react-native-nordic-dfu" 12 | s.license = "Apache License 2.0" 13 | s.platform = :ios, "8.0" 14 | 15 | s.source = { :git => "https://github.com/Pilloxa/react-native-nordic-dfu.git" } 16 | s.source_files = "ios/**/*.{h,m}" 17 | 18 | s.dependency 'React' 19 | s.dependency 'iOSDFULibrary', '~> 4.11.1' 20 | end 21 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'react-native-nordic-dfu' { 2 | export class NordicDFU { 3 | static startDFU({ 4 | deviceAddress, 5 | deviceName, 6 | filePath, 7 | alternativeAdvertisingNameEnabled 8 | }: { 9 | deviceAddress: string; 10 | deviceName?: string; 11 | filePath: string | null; 12 | alternativeAdvertisingNameEnabled?: boolean; 13 | }): Promise; 14 | } 15 | 16 | export interface IDfuUpdate { 17 | percent?: number; 18 | currentPart?: number; 19 | partsTotal?: number; 20 | avgSpeed?: number; 21 | speed?: number; 22 | state?: string; 23 | } 24 | 25 | export class DFUEmitter { 26 | static addListener( 27 | name: 'DFUProgress' | 'DFUStateChanged', 28 | handler: (update: IDfuUpdate) => void 29 | ): void; 30 | 31 | static removeAllListeners(name: 'DFUProgress' | 'DFUStateChanged'): void; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /android/src/main/java/com/pilloxa/dfu/RNNordicDfuPackage.java: -------------------------------------------------------------------------------- 1 | 2 | package com.pilloxa.dfu; 3 | 4 | import java.util.Arrays; 5 | import java.util.Collections; 6 | import java.util.List; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.NativeModule; 10 | import com.facebook.react.bridge.ReactApplicationContext; 11 | import com.facebook.react.uimanager.ViewManager; 12 | import com.facebook.react.bridge.JavaScriptModule; 13 | public class RNNordicDfuPackage implements ReactPackage { 14 | @Override 15 | public List createNativeModules(ReactApplicationContext reactContext) { 16 | return Arrays.asList(new RNNordicDfuModule(reactContext)); 17 | } 18 | 19 | public List> createJSModules() { 20 | return Collections.emptyList(); 21 | } 22 | 23 | @Override 24 | public List createViewManagers(ReactApplicationContext reactContext) { 25 | return Collections.emptyList(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 50 | 51 | fastlane/report.xml 52 | fastlane/Preview.html 53 | fastlane/screenshots 54 | jsconfig.json 55 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 7 4 | environment: 5 | PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/example/node_modules/.bin" 6 | JAVA_OPTS: "-Xms518m -Xmx2048m" 7 | GRADLE_OPTS: '-Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"' 8 | 9 | dependencies: 10 | pre: 11 | - echo y | android update sdk --no-ui --all --filter "android-23" 12 | - echo y | android update sdk --no-ui --all --filter "build-tools-23.0.1" 13 | override: 14 | - cd example && yarn 15 | - cd example/android && ./gradlew --stacktrace app:dependencies 16 | cache_directories: 17 | - ~/.android 18 | - ~/.gradle 19 | 20 | test: 21 | override: 22 | # start the emulator 23 | - emulator -avd circleci-android22 -no-window: 24 | background: true 25 | parallel: true 26 | # wait for it to have booted 27 | - circle-android wait-for-boot 28 | - adb shell pm grant com.backtest android.permission.SYSTEM_ALERT_WINDOW 29 | # make sure that the project can be built 30 | - cd example/android && ./gradlew installDebug 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Pilloxa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-nordic-dfu", 3 | "version": "3.2.1", 4 | "description": "Nordic Device Firmware Update for React Native", 5 | "main": "index.js", 6 | "url": "https://github.com/Pilloxa/react-native-nordic-dfu", 7 | "repository": "Pilloxa/react-native-nordic-dfu", 8 | "scripts": { 9 | "test": "echo \"No test specified\"", 10 | "precommit": "lint-staged", 11 | "document": "documentation readme --readme-file README.md -s \"API\" -g" 12 | }, 13 | "keywords": [ 14 | "react-native", 15 | "dfu", 16 | "nordic" 17 | ], 18 | "author": "Pilloxa ", 19 | "license": "MIT", 20 | "peerDependencies": { 21 | "react-native": ">= 0.45.1" 22 | }, 23 | "devDependencies": { 24 | "documentation": "^4.0.0-rc.1", 25 | "husky": "^0.13.3", 26 | "lint-staged": "^3.4.0", 27 | "prettier": "^1.2.2" 28 | }, 29 | "lint-staged": { 30 | "*.js": [ 31 | "prettier --write", 32 | "git add" 33 | ], 34 | "index.js": [ 35 | "npm run document", 36 | "git add README.md" 37 | ] 38 | }, 39 | "types": "./index.d.ts" 40 | } 41 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, "9.0" 2 | 3 | # External dependencies contain Swift, important to add this line 4 | use_frameworks! 5 | 6 | target "NordicDFUExample" do 7 | # Standard React Native dependencies when using CocoaPods 8 | pod "yoga", path: "../node_modules/react-native/ReactCommon/yoga" 9 | pod "DoubleConversion", podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" 10 | pod "glog", podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" 11 | pod "Folly", podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" 12 | pod "React", path: "../node_modules/react-native", subspecs: [ 13 | "Core", 14 | "CxxBridge", 15 | "DevSupport", 16 | "RCTBlob", 17 | "RCTImage", 18 | "RCTLinkingIOS", 19 | "RCTText", 20 | ] 21 | 22 | pod "react-native-ble-manager", path: "../node_modules/react-native-ble-manager" 23 | pod "rn-fetch-blob", path: "../node_modules/rn-fetch-blob" 24 | 25 | # replace this path with "../node_modules/react-native-nordic-dfu" or wherever 26 | # it's installed in your project 27 | pod "react-native-nordic-dfu", path: "../../" 28 | end 29 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | google() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.1.4' 10 | } 11 | } 12 | 13 | apply plugin: 'com.android.library' 14 | 15 | def DEFAULT_COMPILE_SDK_VERSION = 28 16 | def DEFAULT_BUILD_TOOLS_VERSION = '28.0.3' 17 | def DEFAULT_TARGET_SDK_VERSION = 26 18 | 19 | android { 20 | compileSdkVersion project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION 21 | buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION 22 | 23 | defaultConfig { 24 | minSdkVersion 18 25 | targetSdkVersion project.hasProperty('targetSdkVersion') ? project.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION 26 | versionCode 1 27 | versionName "1.0" 28 | } 29 | lintOptions { 30 | abortOnError false 31 | } 32 | } 33 | 34 | repositories { 35 | mavenCentral() 36 | google() 37 | } 38 | 39 | dependencies { 40 | implementation 'com.facebook.react:react-native:+' 41 | implementation 'no.nordicsemi.android:dfu:1.8.0' 42 | } 43 | 44 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/nordicdfuexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.nordicdfuexample; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.RNFetchBlob.RNFetchBlobPackage; 7 | import com.pilloxa.dfu.RNNordicDfuPackage; 8 | import it.innove.BleManagerPackage; 9 | import com.facebook.react.ReactNativeHost; 10 | import com.facebook.react.ReactPackage; 11 | import com.facebook.react.shell.MainReactPackage; 12 | import com.facebook.soloader.SoLoader; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | public class MainApplication extends Application implements ReactApplication { 18 | 19 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 20 | @Override 21 | public boolean getUseDeveloperSupport() { 22 | return BuildConfig.DEBUG; 23 | } 24 | 25 | @Override 26 | protected List getPackages() { 27 | return Arrays.asList( 28 | new MainReactPackage(), 29 | new RNFetchBlobPackage(), 30 | new RNNordicDfuPackage(), 31 | new BleManagerPackage() 32 | ); 33 | } 34 | }; 35 | 36 | @Override 37 | public ReactNativeHost getReactNativeHost() { 38 | return mReactNativeHost; 39 | } 40 | 41 | @Override 42 | public void onCreate() { 43 | super.onCreate(); 44 | SoLoader.init(this, /* native exopackage */ false); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /example/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | .*/Libraries/react-native/ReactNative.js 16 | 17 | [include] 18 | 19 | [libs] 20 | node_modules/react-native/Libraries/react-native/react-native-interface.js 21 | node_modules/react-native/flow 22 | flow/ 23 | 24 | [options] 25 | emoji=true 26 | 27 | module.system=haste 28 | 29 | experimental.strict_type_args=true 30 | 31 | munge_underscores=true 32 | 33 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 34 | 35 | suppress_type=$FlowIssue 36 | suppress_type=$FlowFixMe 37 | suppress_type=$FixMe 38 | 39 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(4[0-5]\\|[1-3][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 43 | 44 | unsafe.enable_getters_and_setters=true 45 | 46 | [version] 47 | ^0.45.0 48 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | NordicDFUExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /example/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.nordicdfuexample", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.nordicdfuexample", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /android/src/main/java/com/pilloxa/dfu/DfuService.java: -------------------------------------------------------------------------------- 1 | package com.pilloxa.dfu; 2 | 3 | import no.nordicsemi.android.dfu.DfuBaseService; 4 | import android.app.Activity; 5 | 6 | public class DfuService extends DfuBaseService { 7 | 8 | @Override 9 | protected Class getNotificationTarget() { 10 | /* 11 | * As a target activity the NotificationActivity is returned, not the MainActivity. This is because 12 | * the notification must create a new task: 13 | * 14 | * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 15 | * 16 | * when you press it. You can use NotificationActivity to check whether the new activity 17 | * is a root activity (that means no other activity was open earlier) or that some 18 | * other activity is already open. In the latter case the NotificationActivity will just be 19 | * closed. The system will restore the previous activity. However, if the application has been 20 | * closed during upload and you click the notification, a NotificationActivity will 21 | * be launched as a root activity. It will create and start the main activity and 22 | * terminate itself. 23 | * 24 | * This method may be used to restore the target activity in case the application 25 | * was closed or is open. It may also be used to recreate an activity history using 26 | * startActivities(...). 27 | */ 28 | return NotificationActivity.class; 29 | } 30 | 31 | @Override 32 | protected boolean isDebug() { 33 | // Here return true if you want the service to print more logs in LogCat. 34 | // Library's BuildConfig in current version of Android Studio is always set to DEBUG=false, so 35 | // make sure you return true or your.app.BuildConfig.DEBUG here. 36 | return true; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | #import "RNNordicDfu.h" 15 | #import "BleManager.h" 16 | 17 | @implementation AppDelegate 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 20 | { 21 | NSURL *jsCodeLocation; 22 | 23 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 24 | 25 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 26 | moduleName:@"NordicDFUExample" 27 | initialProperties:nil 28 | launchOptions:launchOptions]; 29 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 30 | 31 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 32 | UIViewController *rootViewController = [UIViewController new]; 33 | rootViewController.view = rootView; 34 | self.window.rootViewController = rootViewController; 35 | [self.window makeKeyAndVisible]; 36 | 37 | [RNNordicDfu setCentralManagerGetter:^() { 38 | return [BleManager getCentralManager]; 39 | }]; 40 | 41 | // Reset manager delegate since the Nordic DFU lib "steals" control over it 42 | [RNNordicDfu setOnDFUComplete:^() { 43 | NSLog(@"onDFUComplete"); 44 | CBCentralManager * manager = [BleManager getCentralManager]; 45 | manager.delegate = [BleManager getInstance]; 46 | }]; 47 | [RNNordicDfu setOnDFUError:^() { 48 | NSLog(@"onDFUError"); 49 | CBCentralManager * manager = [BleManager getCentralManager]; 50 | manager.delegate = [BleManager getInstance]; 51 | }]; 52 | 53 | return YES; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /android/src/main/java/com/pilloxa/dfu/NotificationActivity.java: -------------------------------------------------------------------------------- 1 | package com.pilloxa.dfu; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import androidx.annotation.Nullable; 7 | import com.facebook.react.ReactApplication; 8 | import com.facebook.react.ReactInstanceManager; 9 | import com.facebook.react.bridge.ReactContext; 10 | 11 | /** 12 | * Created by viktor on 2017-06-26. 13 | */ 14 | 15 | public class NotificationActivity extends Activity { 16 | 17 | private ReactInstanceManager reactInstanceManager; 18 | 19 | private ReactContext getReactContext() { 20 | reactInstanceManager = ((ReactApplication) getApplication()) 21 | .getReactNativeHost() 22 | .getReactInstanceManager(); 23 | return reactInstanceManager.getCurrentReactContext(); 24 | } 25 | 26 | public Class getMainActivityClass(ReactContext reactContext) { 27 | String packageName = reactContext.getPackageName(); 28 | Intent launchIntent = reactContext.getPackageManager().getLaunchIntentForPackage(packageName); 29 | String className = launchIntent.getComponent().getClassName(); 30 | try { 31 | return Class.forName(className); 32 | } catch (ClassNotFoundException e) { 33 | e.printStackTrace(); 34 | return null; 35 | } 36 | } 37 | 38 | @Override 39 | protected void onCreate(@Nullable Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | // If this activity is the root activity of the task, the app is not running 42 | if (isTaskRoot()) { 43 | ReactContext reactContext = getReactContext(); 44 | Class HostActivity = getMainActivityClass(reactContext); 45 | // Start the app before finishing 46 | final Intent intent = new Intent(this, HostActivity); 47 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 48 | intent.putExtras(getIntent().getExtras()); // copy all extras 49 | startActivity(intent); 50 | } 51 | 52 | // Now finish, which will drop you to the activity at which you were at the top of the task stack 53 | finish(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Disabling obfuscation is useful if you collect stack traces from production crashes 20 | # (unless you are using a system that supports de-obfuscate the stack traces). 21 | -dontobfuscate 22 | 23 | # React Native 24 | 25 | # Keep our interfaces so they can be used by other ProGuard rules. 26 | # See http://sourceforge.net/p/proguard/bugs/466/ 27 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip 28 | -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters 29 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 30 | 31 | # Do not strip any method/class that is annotated with @DoNotStrip 32 | -keep @com.facebook.proguard.annotations.DoNotStrip class * 33 | -keep @com.facebook.common.internal.DoNotStrip class * 34 | -keepclassmembers class * { 35 | @com.facebook.proguard.annotations.DoNotStrip *; 36 | @com.facebook.common.internal.DoNotStrip *; 37 | } 38 | 39 | -keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * { 40 | void set*(***); 41 | *** get*(); 42 | } 43 | 44 | -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } 45 | -keep class * extends com.facebook.react.bridge.NativeModule { *; } 46 | -keepclassmembers,includedescriptorclasses class * { native ; } 47 | -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } 48 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp ; } 49 | -keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup ; } 50 | 51 | -dontwarn com.facebook.react.** 52 | 53 | # TextLayoutBuilder uses a non-public Android constructor within StaticLayout. 54 | # See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details. 55 | -dontwarn android.text.StaticLayout 56 | 57 | # okhttp 58 | 59 | -keepattributes Signature 60 | -keepattributes *Annotation* 61 | -keep class okhttp3.** { *; } 62 | -keep interface okhttp3.** { *; } 63 | -dontwarn okhttp3.** 64 | 65 | # okio 66 | 67 | -keep class sun.misc.Unsafe { *; } 68 | -dontwarn java.nio.file.* 69 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 70 | -dontwarn okio.** 71 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { NativeModules, NativeEventEmitter, Platform } from "react-native"; 2 | const { RNNordicDfu } = NativeModules; 3 | const NordicDFU = { startDFU }; 4 | 5 | function rejectPromise(message) { 6 | return new Promise((resolve, reject) => { 7 | reject(new Error("NordicDFU.startDFU: " + message)); 8 | }); 9 | } 10 | 11 | /** 12 | * 13 | * Starts the DFU process 14 | * 15 | * Observe: The peripheral must have been discovered by the native BLE side so that the 16 | * bluetooth stack knows about it. This library will not do a scan but only 17 | * the actual connect and then the transfer. See the example project to see how it can be 18 | * done in React Native. 19 | * 20 | * For `alternativeAdvertisingNameEnabled` option below, see: 21 | * https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library/blob/master/iOSDFULibrary/Classes/Implementation/DFUServiceInitiator.swift#L191 22 | * 23 | * @param {Object} obj 24 | * @param {string} obj.deviceAddress The MAC address for the device that should be updated 25 | * @param {string} [obj.deviceName = null] The name of the device in the update notification 26 | * @param {string} obj.filePath The file system path to the zip-file used for updating 27 | * @param {Boolean} obj.alternativeAdvertisingNameEnabled Send unique name to device before it is switched into bootloader mode (iOS only) 28 | * @returns {Promise} A promise that resolves or rejects with the `deviceAddress` in the return value 29 | * 30 | * @example 31 | * import { NordicDFU, DFUEmitter } from "react-native-nordic-dfu"; 32 | * 33 | * NordicDFU.startDFU({ 34 | * deviceAddress: "C3:53:C0:39:2F:99", 35 | * deviceName: "Pilloxa Pillbox", 36 | * filePath: "/data/user/0/com.nordicdfuexample/files/RNFetchBlobTmp4of.zip" 37 | * }) 38 | * .then(res => console.log("Transfer done:", res)) 39 | * .catch(console.log); 40 | */ 41 | function startDFU({ 42 | deviceAddress, 43 | deviceName = null, 44 | filePath, 45 | alternativeAdvertisingNameEnabled = true 46 | }) { 47 | if (deviceAddress == undefined) { 48 | return rejectPromise("No deviceAddress defined"); 49 | } 50 | if (filePath == undefined) { 51 | return rejectPromise("No filePath defined"); 52 | } 53 | const upperDeviceAddress = deviceAddress.toUpperCase(); 54 | if (Platform.OS === 'ios') { 55 | return RNNordicDfu.startDFU(upperDeviceAddress, deviceName, filePath, alternativeAdvertisingNameEnabled); 56 | } 57 | return RNNordicDfu.startDFU(upperDeviceAddress, deviceName, filePath); 58 | } 59 | 60 | /** 61 | * Event emitter for DFU state and progress events 62 | * 63 | * @const DFUEmitter 64 | * 65 | * @example 66 | * import { NordicDFU, DFUEmitter } from "react-native-nordic-dfu"; 67 | * 68 | * DFUEmitter.addlistener("DFUProgress",({percent, currentPart, partsTotal, avgSpeed, speed}) => { 69 | * console.log("DFU progress: " + percent +"%"); 70 | * }); 71 | * 72 | * DFUEmitter.addListener("DFUStateChanged", ({state}) => { 73 | * console.log("DFU State:", state); 74 | * }) 75 | */ 76 | const DFUEmitter = new NativeEventEmitter(RNNordicDfu); 77 | 78 | export { NordicDFU, DFUEmitter }; 79 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - boost-for-react-native (1.63.0) 3 | - DoubleConversion (1.1.6) 4 | - Folly (2018.10.22.00): 5 | - boost-for-react-native 6 | - DoubleConversion 7 | - glog 8 | - glog (0.3.5) 9 | - iOSDFULibrary (4.4.1): 10 | - ZIPFoundation (~> 0.9.9) 11 | - React (0.59.4): 12 | - React/Core (= 0.59.4) 13 | - react-native-ble-manager (6.6.2): 14 | - React 15 | - react-native-nordic-dfu (3.0.0): 16 | - iOSDFULibrary (~> 4.4.0) 17 | - React 18 | - ZIPFoundation (~> 0.9.8) 19 | - React/Core (0.59.4): 20 | - yoga (= 0.59.4.React) 21 | - React/CxxBridge (0.59.4): 22 | - Folly (= 2018.10.22.00) 23 | - React/Core 24 | - React/cxxreact 25 | - React/jsiexecutor 26 | - React/cxxreact (0.59.4): 27 | - boost-for-react-native (= 1.63.0) 28 | - DoubleConversion 29 | - Folly (= 2018.10.22.00) 30 | - glog 31 | - React/jsinspector 32 | - React/DevSupport (0.59.4): 33 | - React/Core 34 | - React/RCTWebSocket 35 | - React/fishhook (0.59.4) 36 | - React/jsi (0.59.4): 37 | - DoubleConversion 38 | - Folly (= 2018.10.22.00) 39 | - glog 40 | - React/jsiexecutor (0.59.4): 41 | - DoubleConversion 42 | - Folly (= 2018.10.22.00) 43 | - glog 44 | - React/cxxreact 45 | - React/jsi 46 | - React/jsinspector (0.59.4) 47 | - React/RCTBlob (0.59.4): 48 | - React/Core 49 | - React/RCTImage (0.59.4): 50 | - React/Core 51 | - React/RCTNetwork 52 | - React/RCTLinkingIOS (0.59.4): 53 | - React/Core 54 | - React/RCTNetwork (0.59.4): 55 | - React/Core 56 | - React/RCTText (0.59.4): 57 | - React/Core 58 | - React/RCTWebSocket (0.59.4): 59 | - React/Core 60 | - React/fishhook 61 | - React/RCTBlob 62 | - rn-fetch-blob (0.10.6): 63 | - React/Core 64 | - yoga (0.59.4.React) 65 | - ZIPFoundation (0.9.9) 66 | 67 | DEPENDENCIES: 68 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) 69 | - Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`) 70 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) 71 | - react-native-ble-manager (from `../node_modules/react-native-ble-manager`) 72 | - react-native-nordic-dfu (from `../../`) 73 | - React/Core (from `../node_modules/react-native`) 74 | - React/CxxBridge (from `../node_modules/react-native`) 75 | - React/DevSupport (from `../node_modules/react-native`) 76 | - React/RCTBlob (from `../node_modules/react-native`) 77 | - React/RCTImage (from `../node_modules/react-native`) 78 | - React/RCTLinkingIOS (from `../node_modules/react-native`) 79 | - React/RCTText (from `../node_modules/react-native`) 80 | - rn-fetch-blob (from `../node_modules/rn-fetch-blob`) 81 | - yoga (from `../node_modules/react-native/ReactCommon/yoga`) 82 | 83 | SPEC REPOS: 84 | https://github.com/cocoapods/specs.git: 85 | - boost-for-react-native 86 | - iOSDFULibrary 87 | - ZIPFoundation 88 | 89 | EXTERNAL SOURCES: 90 | DoubleConversion: 91 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" 92 | Folly: 93 | :podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec" 94 | glog: 95 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" 96 | React: 97 | :path: "../node_modules/react-native" 98 | react-native-ble-manager: 99 | :path: "../node_modules/react-native-ble-manager" 100 | react-native-nordic-dfu: 101 | :path: "../../" 102 | rn-fetch-blob: 103 | :path: "../node_modules/rn-fetch-blob" 104 | yoga: 105 | :path: "../node_modules/react-native/ReactCommon/yoga" 106 | 107 | SPEC CHECKSUMS: 108 | boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c 109 | DoubleConversion: bb338842f62ab1d708ceb63ec3d999f0f3d98ecd 110 | Folly: de497beb10f102453a1afa9edbf8cf8a251890de 111 | glog: aefd1eb5dda2ab95ba0938556f34b98e2da3a60d 112 | iOSDFULibrary: cd43d0c1db731dbc116a67d55ea23d4c39d16c40 113 | React: 5cb71fb1a15b5ce04794ab49e24b48ebe4c94e65 114 | react-native-ble-manager: ea54402df086ead2c234e360b41606f206a2e8b8 115 | react-native-nordic-dfu: 13c96e0093d89d9a018ac4cffce6c964436756b1 116 | rn-fetch-blob: 766f85cabd2992300dfa1be2bc9e4e258abc6f04 117 | yoga: 596e61c9b57751d08a22b07aba310dbd3e65ab75 118 | ZIPFoundation: 89df685c971926b0323087952320bdfee9f0b6ef 119 | 120 | PODFILE CHECKSUM: cb820ecf6246ea4ab1fde3a11b0880f6cc0f1108 121 | 122 | COCOAPODS: 1.6.1 123 | -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * An example project that downloads a zip file, connects to a device and then flashes 3 | * it. 4 | */ 5 | 6 | import React, { Component } from "react"; 7 | import { 8 | AppRegistry, 9 | TouchableHighlight, 10 | NativeModules, 11 | NativeEventEmitter, 12 | Platform, 13 | StyleSheet, 14 | Text, 15 | View, 16 | Image 17 | } from "react-native"; 18 | import { NordicDFU, DFUEmitter } from "react-native-nordic-dfu"; 19 | import RNFetchBlob from "rn-fetch-blob"; 20 | import BleManager from "react-native-ble-manager"; 21 | 22 | const BleManagerModule = NativeModules.BleManager; 23 | const bleManagerEmitter = new NativeEventEmitter(BleManagerModule); 24 | const DEVICE_ID = "C3:53:A0:31:2F:14"; 25 | 26 | const FB = RNFetchBlob.config({ 27 | fileCache: true, 28 | appendExt: "zip" 29 | }); 30 | 31 | export default class NordicDFUExample extends Component { 32 | constructor(props) { 33 | super(props); 34 | this.handleDeviceDiscovered = this.handleDeviceDiscovered.bind(this); 35 | this.startScan = this.startScan.bind(this); 36 | this.handleStopScan = this.handleStopScan.bind(this); 37 | this.state = { 38 | imagefile: false, 39 | scanning: false, 40 | deviceFound: false, 41 | dfuState: "Not started", 42 | progress: 0 43 | }; 44 | } 45 | 46 | componentDidMount() { 47 | DFUEmitter.addListener("DFUProgress", ({ percent }) => { 48 | console.log("DFU progress:", percent); 49 | this.setState({ progress: percent }); 50 | }); 51 | DFUEmitter.addListener("DFUStateChanged", ({ state }) => { 52 | console.log("DFU state:", state); 53 | this.setState({ dfuState: state }); 54 | }); 55 | 56 | FB.fetch("GET", "http://localhost:1234/app.zip").then(res => { 57 | console.log("file saved to", res.path()); 58 | this.setState({ imagefile: res.path() }); 59 | }); 60 | 61 | BleManager.start({ showAlert: false, allowDuplicates: false }); 62 | bleManagerEmitter.addListener("BleManagerStopScan", this.handleStopScan); 63 | bleManagerEmitter.addListener( 64 | "BleManagerDiscoverPeripheral", 65 | this.handleDeviceDiscovered 66 | ); 67 | this.startScan(); 68 | } 69 | 70 | // #### DFU ####################################################### 71 | 72 | startDFU() { 73 | console.log("Starting DFU"); 74 | NordicDFU.startDFU({ 75 | deviceAddress: DEVICE_ID, 76 | name: "Pilloxa Board", 77 | filePath: this.state.imagefile 78 | }) 79 | .then(res => console.log("Transfer done: ", res)) 80 | .catch(console.log); 81 | } 82 | 83 | // #### BLUETOOTH ################################################# 84 | 85 | handleDeviceDiscovered({ id }) { 86 | if (id == DEVICE_ID) { 87 | this.setState({ 88 | deviceFound: true, 89 | scanning: false 90 | }); 91 | } 92 | } 93 | 94 | handleStopScan() { 95 | console.log("Scan is stopped"); 96 | if (this.state.scanning) { 97 | this.startScan(); 98 | } 99 | } 100 | 101 | startScan() { 102 | BleManager.scan([], 3, true).then(results => { 103 | console.log("Scanning..."); 104 | this.setState({ scanning: true }); 105 | }); 106 | } 107 | 108 | // #### RENDER ######################################################### 109 | 110 | render() { 111 | return ( 112 | 113 | 114 | {this.state.dfuState} 115 | 116 | 117 | {"DFU progress: " + this.state.progress + " %"} 118 | 119 | 120 | {this.state.scanning ? "Scanning for: " + DEVICE_ID : "Not scanning"} 121 | 122 | 123 | {this.state.deviceFound 124 | ? "Found device: " + DEVICE_ID 125 | : "Device not found"} 126 | 127 | 128 | {this.state.deviceFound 129 | ? 133 | Start DFU 134 | 135 | : null} 136 | 137 | ); 138 | } 139 | } 140 | 141 | const styles = StyleSheet.create({ 142 | container: { 143 | flex: 1, 144 | justifyContent: "center", 145 | alignItems: "center", 146 | backgroundColor: "#F5FCFF" 147 | }, 148 | welcome: { 149 | fontSize: 20, 150 | textAlign: "center", 151 | margin: 10 152 | }, 153 | instructions: { 154 | textAlign: "center", 155 | color: "#333333", 156 | marginBottom: 5 157 | } 158 | }); 159 | 160 | AppRegistry.registerComponent("NordicDFUExample", () => NordicDFUExample); 161 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample.xcodeproj/xcshareddata/xcschemes/NordicDFUExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 57 | 63 | 64 | 65 | 66 | 67 | 72 | 73 | 75 | 81 | 82 | 83 | 84 | 85 | 91 | 92 | 93 | 94 | 95 | 96 | 106 | 108 | 114 | 115 | 116 | 117 | 118 | 119 | 125 | 127 | 133 | 134 | 135 | 136 | 138 | 139 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | 3 | import com.android.build.OutputFile 4 | 5 | /** 6 | * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets 7 | * and bundleReleaseJsAndAssets). 8 | * These basically call `react-native bundle` with the correct arguments during the Android build 9 | * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the 10 | * bundle directly from the development server. Below you can see all the possible configurations 11 | * and their defaults. If you decide to add a configuration block, make sure to add it before the 12 | * `apply from: "../../node_modules/react-native/react.gradle"` line. 13 | * 14 | * project.ext.react = [ 15 | * // the name of the generated asset file containing your JS bundle 16 | * bundleAssetName: "index.android.bundle", 17 | * 18 | * // the entry file for bundle generation 19 | * entryFile: "index.android.js", 20 | * 21 | * // whether to bundle JS and assets in debug mode 22 | * bundleInDebug: false, 23 | * 24 | * // whether to bundle JS and assets in release mode 25 | * bundleInRelease: true, 26 | * 27 | * // whether to bundle JS and assets in another build variant (if configured). 28 | * // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants 29 | * // The configuration property can be in the following formats 30 | * // 'bundleIn${productFlavor}${buildType}' 31 | * // 'bundleIn${buildType}' 32 | * // bundleInFreeDebug: true, 33 | * // bundleInPaidRelease: true, 34 | * // bundleInBeta: true, 35 | * 36 | * // whether to disable dev mode in custom build variants (by default only disabled in release) 37 | * // for example: to disable dev mode in the staging build type (if configured) 38 | * devDisabledInStaging: true, 39 | * // The configuration property can be in the following formats 40 | * // 'devDisabledIn${productFlavor}${buildType}' 41 | * // 'devDisabledIn${buildType}' 42 | * 43 | * // the root of your project, i.e. where "package.json" lives 44 | * root: "../../", 45 | * 46 | * // where to put the JS bundle asset in debug mode 47 | * jsBundleDirDebug: "$buildDir/intermediates/assets/debug", 48 | * 49 | * // where to put the JS bundle asset in release mode 50 | * jsBundleDirRelease: "$buildDir/intermediates/assets/release", 51 | * 52 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 53 | * // require('./image.png')), in debug mode 54 | * resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", 55 | * 56 | * // where to put drawable resources / React Native assets, e.g. the ones you use via 57 | * // require('./image.png')), in release mode 58 | * resourcesDirRelease: "$buildDir/intermediates/res/merged/release", 59 | * 60 | * // by default the gradle tasks are skipped if none of the JS files or assets change; this means 61 | * // that we don't look at files in android/ or ios/ to determine whether the tasks are up to 62 | * // date; if you have any other folders that you want to ignore for performance reasons (gradle 63 | * // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ 64 | * // for example, you might want to remove it from here. 65 | * inputExcludes: ["android/**", "ios/**"], 66 | * 67 | * // override which node gets called and with what additional arguments 68 | * nodeExecutableAndArgs: ["node"], 69 | * 70 | * // supply additional arguments to the packager 71 | * extraPackagerArgs: [] 72 | * ] 73 | */ 74 | 75 | apply from: "../../node_modules/react-native/react.gradle" 76 | 77 | /** 78 | * Set this to true to create two separate APKs instead of one: 79 | * - An APK that only works on ARM devices 80 | * - An APK that only works on x86 devices 81 | * The advantage is the size of the APK is reduced by about 4MB. 82 | * Upload all the APKs to the Play Store and people will download 83 | * the correct one based on the CPU architecture of their device. 84 | */ 85 | def enableSeparateBuildPerCPUArchitecture = false 86 | 87 | /** 88 | * Run Proguard to shrink the Java bytecode in release builds. 89 | */ 90 | def enableProguardInReleaseBuilds = false 91 | 92 | android { 93 | compileSdkVersion 23 94 | buildToolsVersion '23.0.1' 95 | 96 | defaultConfig { 97 | applicationId "com.nordicdfuexample" 98 | minSdkVersion 18 99 | targetSdkVersion 22 100 | versionCode 1 101 | versionName "1.0" 102 | ndk { 103 | abiFilters "armeabi-v7a", "x86" 104 | } 105 | } 106 | splits { 107 | abi { 108 | reset() 109 | enable enableSeparateBuildPerCPUArchitecture 110 | universalApk false // If true, also generate a universal APK 111 | include "armeabi-v7a", "x86" 112 | } 113 | } 114 | buildTypes { 115 | release { 116 | minifyEnabled enableProguardInReleaseBuilds 117 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 118 | } 119 | } 120 | // applicationVariants are e.g. debug, release 121 | applicationVariants.all { variant -> 122 | variant.outputs.each { output -> 123 | // For each separate APK per architecture, set a unique version code as described here: 124 | // http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits 125 | def versionCodes = ["armeabi-v7a":1, "x86":2] 126 | def abi = output.getFilter(OutputFile.ABI) 127 | if (abi != null) { // null for the universal-debug, universal-release variants 128 | output.versionCodeOverride = 129 | versionCodes.get(abi) * 1048576 + defaultConfig.versionCode 130 | } 131 | } 132 | } 133 | } 134 | 135 | dependencies { 136 | compile project(':react-native-fetch-blob') 137 | compile project(':react-native-nordic-dfu') 138 | compile project(':react-native-ble-manager') 139 | compile fileTree(dir: "libs", include: ["*.jar"]) 140 | compile "com.android.support:appcompat-v7:23.0.1" 141 | compile "com.facebook.react:react-native:+" // From node_modules 142 | } 143 | 144 | // Run this once to be able to run the application with BUCK 145 | // puts all compile dependencies into folder libs for BUCK to use 146 | task copyDownloadableDepsToLibs(type: Copy) { 147 | from configurations.compile 148 | into 'libs' 149 | } 150 | -------------------------------------------------------------------------------- /android/src/main/java/com/pilloxa/dfu/RNNordicDfuModule.java: -------------------------------------------------------------------------------- 1 | 2 | package com.pilloxa.dfu; 3 | 4 | import android.app.NotificationManager; 5 | import android.content.Context; 6 | import android.os.Build; 7 | import android.os.Handler; 8 | import androidx.annotation.Nullable; 9 | import android.util.Log; 10 | import com.facebook.react.bridge.*; 11 | import com.facebook.react.modules.core.RCTNativeAppEventEmitter; 12 | import no.nordicsemi.android.dfu.*; 13 | 14 | public class RNNordicDfuModule extends ReactContextBaseJavaModule implements LifecycleEventListener { 15 | 16 | private final String dfuStateEvent = "DFUStateChanged"; 17 | private final String progressEvent = "DFUProgress"; 18 | private static final String name = "RNNordicDfu"; 19 | public static final String LOG_TAG = name; 20 | private final ReactApplicationContext reactContext; 21 | private Promise mPromise = null; 22 | 23 | public RNNordicDfuModule(ReactApplicationContext reactContext) { 24 | super(reactContext); 25 | reactContext.addLifecycleEventListener(this); 26 | this.reactContext = reactContext; 27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 28 | DfuServiceInitiator.createDfuNotificationChannel(reactContext); 29 | } 30 | } 31 | 32 | @ReactMethod 33 | public void startDFU(String address, String name, String filePath, Promise promise) { 34 | mPromise = promise; 35 | final DfuServiceInitiator starter = new DfuServiceInitiator(address) 36 | .setKeepBond(false); 37 | if (name != null) { 38 | starter.setDeviceName(name); 39 | } 40 | starter.setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true); 41 | starter.setZip(filePath); 42 | final DfuServiceController controller = starter.start(this.reactContext, DfuService.class); 43 | } 44 | 45 | @Override 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | 51 | private void sendEvent(String eventName, @Nullable WritableMap params) { 52 | getReactApplicationContext() 53 | .getJSModule(RCTNativeAppEventEmitter.class) 54 | .emit(eventName, params); 55 | } 56 | 57 | private void sendStateUpdate(String state, String deviceAddress) { 58 | WritableMap map = new WritableNativeMap(); 59 | Log.d(LOG_TAG, "State: " + state); 60 | map.putString("state", state); 61 | map.putString("deviceAddress", deviceAddress); 62 | sendEvent(dfuStateEvent, map); 63 | } 64 | 65 | 66 | @Override 67 | public void onHostResume() { 68 | DfuServiceListenerHelper.registerProgressListener(this.reactContext, mDfuProgressListener); 69 | 70 | } 71 | 72 | @Override 73 | public void onHostPause() { 74 | } 75 | 76 | @Override 77 | public void onHostDestroy() { 78 | DfuServiceListenerHelper.unregisterProgressListener(this.reactContext, mDfuProgressListener); 79 | 80 | } 81 | 82 | 83 | /** 84 | * The progress listener receives events from the DFU Service. 85 | * If is registered in onCreate() and unregistered in onDestroy() so methods here may also be called 86 | * when the screen is locked or the app went to the background. This is because the UI needs to have the 87 | * correct information after user comes back to the activity and this information can't be read from the service 88 | * as it might have been killed already (DFU completed or finished with error). 89 | */ 90 | private final DfuProgressListener mDfuProgressListener = new DfuProgressListenerAdapter() { 91 | @Override 92 | public void onDeviceConnecting(final String deviceAddress) { 93 | sendStateUpdate("CONNECTING", deviceAddress); 94 | } 95 | 96 | @Override 97 | public void onDfuProcessStarting(final String deviceAddress) { 98 | sendStateUpdate("DFU_PROCESS_STARTING", deviceAddress); 99 | } 100 | 101 | @Override 102 | public void onEnablingDfuMode(final String deviceAddress) { 103 | sendStateUpdate("ENABLING_DFU_MODE", deviceAddress); 104 | } 105 | 106 | @Override 107 | public void onFirmwareValidating(final String deviceAddress) { 108 | sendStateUpdate("FIRMWARE_VALIDATING", deviceAddress); 109 | } 110 | 111 | @Override 112 | public void onDeviceDisconnecting(final String deviceAddress) { 113 | sendStateUpdate("DEVICE_DISCONNECTING", deviceAddress); 114 | } 115 | 116 | @Override 117 | public void onDfuCompleted(final String deviceAddress) { 118 | if (mPromise != null) { 119 | WritableMap map = new WritableNativeMap(); 120 | map.putString("deviceAddress", deviceAddress); 121 | mPromise.resolve(map); 122 | mPromise = null; 123 | } 124 | sendStateUpdate("DFU_COMPLETED", deviceAddress); 125 | 126 | 127 | new Handler().postDelayed(new Runnable() { 128 | @Override 129 | public void run() { 130 | 131 | // if this activity is still open and upload process was completed, cancel the notification 132 | final NotificationManager manager = (NotificationManager) reactContext.getSystemService(Context.NOTIFICATION_SERVICE); 133 | manager.cancel(DfuService.NOTIFICATION_ID); 134 | } 135 | }, 200); 136 | 137 | } 138 | 139 | @Override 140 | public void onDfuAborted(final String deviceAddress) { 141 | sendStateUpdate("DFU_ABORTED", deviceAddress); 142 | if (mPromise != null) { 143 | mPromise.reject("2", "DFU ABORTED"); 144 | mPromise = null; 145 | } 146 | 147 | } 148 | 149 | @Override 150 | public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) { 151 | WritableMap map = new WritableNativeMap(); 152 | map.putString("deviceAddress", deviceAddress); 153 | map.putInt("percent", percent); 154 | map.putDouble("speed", speed); 155 | map.putDouble("avgSpeed", avgSpeed); 156 | map.putInt("currentPart", currentPart); 157 | map.putInt("partsTotal", partsTotal); 158 | sendEvent(progressEvent, map); 159 | 160 | } 161 | 162 | @Override 163 | public void onError(final String deviceAddress, final int error, final int errorType, final String message) { 164 | sendStateUpdate("DFU_FAILED", deviceAddress); 165 | if (mPromise != null) { 166 | mPromise.reject(Integer.toString(error), message); 167 | mPromise = null; 168 | } 169 | } 170 | }; 171 | } -------------------------------------------------------------------------------- /ios/RNNordicDfu.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B3E7B58A1CC2AC0600A0062D /* RNNordicDfu.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNNordicDfu.m */; }; 11 | /* End PBXBuildFile section */ 12 | 13 | /* Begin PBXCopyFilesBuildPhase section */ 14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 15 | isa = PBXCopyFilesBuildPhase; 16 | buildActionMask = 2147483647; 17 | dstPath = "include/$(PRODUCT_NAME)"; 18 | dstSubfolderSpec = 16; 19 | files = ( 20 | ); 21 | runOnlyForDeploymentPostprocessing = 0; 22 | }; 23 | /* End PBXCopyFilesBuildPhase section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | 134814201AA4EA6300B7C361 /* libRNNordicDfu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNNordicDfu.a; sourceTree = BUILT_PRODUCTS_DIR; }; 27 | B3E7B5881CC2AC0600A0062D /* RNNordicDfu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNNordicDfu.h; sourceTree = ""; }; 28 | B3E7B5891CC2AC0600A0062D /* RNNordicDfu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNNordicDfu.m; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | ); 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXFrameworksBuildPhase section */ 40 | 41 | /* Begin PBXGroup section */ 42 | 134814211AA4EA7D00B7C361 /* Products */ = { 43 | isa = PBXGroup; 44 | children = ( 45 | 134814201AA4EA6300B7C361 /* libRNNordicDfu.a */, 46 | ); 47 | name = Products; 48 | sourceTree = ""; 49 | }; 50 | 58B511D21A9E6C8500147676 = { 51 | isa = PBXGroup; 52 | children = ( 53 | B3E7B5881CC2AC0600A0062D /* RNNordicDfu.h */, 54 | B3E7B5891CC2AC0600A0062D /* RNNordicDfu.m */, 55 | 134814211AA4EA7D00B7C361 /* Products */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXNativeTarget section */ 62 | 58B511DA1A9E6C8500147676 /* RNNordicDfu */ = { 63 | isa = PBXNativeTarget; 64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNordicDfu" */; 65 | buildPhases = ( 66 | 58B511D71A9E6C8500147676 /* Sources */, 67 | 58B511D81A9E6C8500147676 /* Frameworks */, 68 | 58B511D91A9E6C8500147676 /* CopyFiles */, 69 | ); 70 | buildRules = ( 71 | ); 72 | dependencies = ( 73 | ); 74 | name = RNNordicDfu; 75 | productName = RCTDataManager; 76 | productReference = 134814201AA4EA6300B7C361 /* libRNNordicDfu.a */; 77 | productType = "com.apple.product-type.library.static"; 78 | }; 79 | /* End PBXNativeTarget section */ 80 | 81 | /* Begin PBXProject section */ 82 | 58B511D31A9E6C8500147676 /* Project object */ = { 83 | isa = PBXProject; 84 | attributes = { 85 | LastUpgradeCheck = 0610; 86 | ORGANIZATIONNAME = Facebook; 87 | TargetAttributes = { 88 | 58B511DA1A9E6C8500147676 = { 89 | CreatedOnToolsVersion = 6.1.1; 90 | }; 91 | }; 92 | }; 93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNordicDfu" */; 94 | compatibilityVersion = "Xcode 3.2"; 95 | developmentRegion = English; 96 | hasScannedForEncodings = 0; 97 | knownRegions = ( 98 | en, 99 | ); 100 | mainGroup = 58B511D21A9E6C8500147676; 101 | productRefGroup = 58B511D21A9E6C8500147676; 102 | projectDirPath = ""; 103 | projectRoot = ""; 104 | targets = ( 105 | 58B511DA1A9E6C8500147676 /* RNNordicDfu */, 106 | ); 107 | }; 108 | /* End PBXProject section */ 109 | 110 | /* Begin PBXSourcesBuildPhase section */ 111 | 58B511D71A9E6C8500147676 /* Sources */ = { 112 | isa = PBXSourcesBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | B3E7B58A1CC2AC0600A0062D /* RNNordicDfu.m in Sources */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXSourcesBuildPhase section */ 120 | 121 | /* Begin XCBuildConfiguration section */ 122 | 58B511ED1A9E6C8500147676 /* Debug */ = { 123 | isa = XCBuildConfiguration; 124 | buildSettings = { 125 | ALWAYS_SEARCH_USER_PATHS = NO; 126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 127 | CLANG_CXX_LIBRARY = "libc++"; 128 | CLANG_ENABLE_MODULES = YES; 129 | CLANG_ENABLE_OBJC_ARC = YES; 130 | CLANG_WARN_BOOL_CONVERSION = YES; 131 | CLANG_WARN_CONSTANT_CONVERSION = YES; 132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 133 | CLANG_WARN_EMPTY_BODY = YES; 134 | CLANG_WARN_ENUM_CONVERSION = YES; 135 | CLANG_WARN_INT_CONVERSION = YES; 136 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 137 | CLANG_WARN_UNREACHABLE_CODE = YES; 138 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 139 | COPY_PHASE_STRIP = NO; 140 | ENABLE_STRICT_OBJC_MSGSEND = YES; 141 | GCC_C_LANGUAGE_STANDARD = gnu99; 142 | GCC_DYNAMIC_NO_PIC = NO; 143 | GCC_OPTIMIZATION_LEVEL = 0; 144 | GCC_PREPROCESSOR_DEFINITIONS = ( 145 | "DEBUG=1", 146 | "$(inherited)", 147 | ); 148 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 149 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 150 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 151 | GCC_WARN_UNDECLARED_SELECTOR = YES; 152 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 153 | GCC_WARN_UNUSED_FUNCTION = YES; 154 | GCC_WARN_UNUSED_VARIABLE = YES; 155 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 156 | MTL_ENABLE_DEBUG_INFO = YES; 157 | ONLY_ACTIVE_ARCH = YES; 158 | SDKROOT = iphoneos; 159 | }; 160 | name = Debug; 161 | }; 162 | 58B511EE1A9E6C8500147676 /* Release */ = { 163 | isa = XCBuildConfiguration; 164 | buildSettings = { 165 | ALWAYS_SEARCH_USER_PATHS = NO; 166 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 167 | CLANG_CXX_LIBRARY = "libc++"; 168 | CLANG_ENABLE_MODULES = YES; 169 | CLANG_ENABLE_OBJC_ARC = YES; 170 | CLANG_WARN_BOOL_CONVERSION = YES; 171 | CLANG_WARN_CONSTANT_CONVERSION = YES; 172 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 173 | CLANG_WARN_EMPTY_BODY = YES; 174 | CLANG_WARN_ENUM_CONVERSION = YES; 175 | CLANG_WARN_INT_CONVERSION = YES; 176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 177 | CLANG_WARN_UNREACHABLE_CODE = YES; 178 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 179 | COPY_PHASE_STRIP = YES; 180 | ENABLE_NS_ASSERTIONS = NO; 181 | ENABLE_STRICT_OBJC_MSGSEND = YES; 182 | GCC_C_LANGUAGE_STANDARD = gnu99; 183 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 184 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 185 | GCC_WARN_UNDECLARED_SELECTOR = YES; 186 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 187 | GCC_WARN_UNUSED_FUNCTION = YES; 188 | GCC_WARN_UNUSED_VARIABLE = YES; 189 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 190 | MTL_ENABLE_DEBUG_INFO = NO; 191 | SDKROOT = iphoneos; 192 | VALIDATE_PRODUCT = YES; 193 | }; 194 | name = Release; 195 | }; 196 | 58B511F01A9E6C8500147676 /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; 200 | HEADER_SEARCH_PATHS = ( 201 | "$(inherited)", 202 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 203 | "$(SRCROOT)/../../../React/**", 204 | "$(SRCROOT)/../../react-native/React/**", 205 | "$(PROJECT_DIR)/iOSDFULibrary.framework/**", 206 | "$(PROJECT_DIR)/../../../ios/Pods/Headers/Public/**", 207 | ); 208 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 209 | OTHER_LDFLAGS = "-ObjC"; 210 | PRODUCT_NAME = RNNordicDfu; 211 | SKIP_INSTALL = YES; 212 | }; 213 | name = Debug; 214 | }; 215 | 58B511F11A9E6C8500147676 /* Release */ = { 216 | isa = XCBuildConfiguration; 217 | buildSettings = { 218 | FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/**"; 219 | HEADER_SEARCH_PATHS = ( 220 | "$(inherited)", 221 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 222 | "$(SRCROOT)/../../../React/**", 223 | "$(SRCROOT)/../../react-native/React/**", 224 | "$(PROJECT_DIR)/iOSDFULibrary.framework/**", 225 | "$(PROJECT_DIR)/../../../ios/Pods/Headers/Public/**", 226 | ); 227 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 228 | OTHER_LDFLAGS = "-ObjC"; 229 | PRODUCT_NAME = RNNordicDfu; 230 | SKIP_INSTALL = YES; 231 | }; 232 | name = Release; 233 | }; 234 | /* End XCBuildConfiguration section */ 235 | 236 | /* Begin XCConfigurationList section */ 237 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNNordicDfu" */ = { 238 | isa = XCConfigurationList; 239 | buildConfigurations = ( 240 | 58B511ED1A9E6C8500147676 /* Debug */, 241 | 58B511EE1A9E6C8500147676 /* Release */, 242 | ); 243 | defaultConfigurationIsVisible = 0; 244 | defaultConfigurationName = Release; 245 | }; 246 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNNordicDfu" */ = { 247 | isa = XCConfigurationList; 248 | buildConfigurations = ( 249 | 58B511F01A9E6C8500147676 /* Debug */, 250 | 58B511F11A9E6C8500147676 /* Release */, 251 | ); 252 | defaultConfigurationIsVisible = 0; 253 | defaultConfigurationName = Release; 254 | }; 255 | /* End XCConfigurationList section */ 256 | }; 257 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 258 | } 259 | -------------------------------------------------------------------------------- /ios/RNNordicDfu.m: -------------------------------------------------------------------------------- 1 | #import "RNNordicDfu.h" 2 | #import 3 | @import iOSDFULibrary; 4 | 5 | static CBCentralManager * (^getCentralManager)(); 6 | static void (^onDFUComplete)(); 7 | static void (^onDFUError)(); 8 | 9 | @implementation RNNordicDfu 10 | 11 | RCT_EXPORT_MODULE(); 12 | 13 | NSString * const DFUProgressEvent = @"DFUProgress"; 14 | NSString * const DFUStateChangedEvent = @"DFUStateChanged"; 15 | 16 | - (NSArray *)supportedEvents 17 | { 18 | return @[DFUProgressEvent, 19 | DFUStateChangedEvent,]; 20 | } 21 | 22 | - (NSString *)stateDescription:(enum DFUState)state 23 | { 24 | switch (state) 25 | { 26 | case DFUStateAborted: 27 | return @"DFU_ABORTED"; 28 | case DFUStateStarting: 29 | return @"DFU_PROCESS_STARTING"; 30 | case DFUStateCompleted: 31 | return @"DFU_COMPLETED"; 32 | case DFUStateUploading: 33 | return @"DFU_STATE_UPLOADING"; 34 | case DFUStateConnecting: 35 | return @"CONNECTING"; 36 | case DFUStateValidating: 37 | return @"FIRMWARE_VALIDATING"; 38 | case DFUStateDisconnecting: 39 | return @"DEVICE_DISCONNECTING"; 40 | case DFUStateEnablingDfuMode: 41 | return @"ENABLING_DFU_MODE"; 42 | default: 43 | return @"UNKNOWN_STATE"; 44 | } 45 | } 46 | 47 | - (NSString *)errorDescription:(enum DFUError)error 48 | { 49 | switch(error) 50 | { 51 | case DFUErrorCrcError: 52 | return @"DFUErrorCrcError"; 53 | case DFUErrorBytesLost: 54 | return @"DFUErrorBytesLost"; 55 | case DFUErrorFileInvalid: 56 | return @"DFUErrorFileInvalid"; 57 | case DFUErrorFailedToConnect: 58 | return @"DFUErrorFailedToConnect"; 59 | case DFUErrorFileNotSpecified: 60 | return @"DFUErrorFileNotSpecified"; 61 | case DFUErrorBluetoothDisabled: 62 | return @"DFUErrorBluetoothDisabled"; 63 | case DFUErrorDeviceDisconnected: 64 | return @"DFUErrorDeviceDisconnected"; 65 | case DFUErrorDeviceNotSupported: 66 | return @"DFUErrorDeviceNotSupported"; 67 | case DFUErrorInitPacketRequired: 68 | return @"DFUErrorInitPacketRequired"; 69 | case DFUErrorUnsupportedResponse: 70 | return @"DFUErrorUnsupportedResponse"; 71 | case DFUErrorReadingVersionFailed: 72 | return @"DFUErrorReadingVersionFailed"; 73 | case DFUErrorRemoteLegacyDFUSuccess: 74 | return @"DFUErrorRemoteLegacyDFUSuccess"; 75 | case DFUErrorRemoteSecureDFUSuccess: 76 | return @"DFUErrorRemoteSecureDFUSuccess"; 77 | case DFUErrorServiceDiscoveryFailed: 78 | return @"DFUErrorServiceDiscoveryFailed"; 79 | case DFUErrorRemoteLegacyDFUCrcError: 80 | return @"DFUErrorRemoteLegacyDFUCrcError"; 81 | case DFUErrorEnablingControlPointFailed: 82 | return @"DFUErrorEnablingControlPointFailed"; 83 | case DFUErrorExtendedInitPacketRequired: 84 | return @"DFUErrorExtendedInitPacketRequired"; 85 | case DFUErrorReceivingNotificationFailed: 86 | return @"DFUErrorReceivingNotificationFailed"; 87 | case DFUErrorRemoteButtonlessDFUSuccess: 88 | return @"DFUErrorRemoteButtonlessDFUSuccess"; 89 | case DFUErrorRemoteLegacyDFUInvalidState: 90 | return @"DFUErrorRemoteLegacyDFUInvalidState"; 91 | case DFUErrorRemoteLegacyDFUNotSupported: 92 | return @"DFUErrorRemoteLegacyDFUNotSupported"; 93 | case DFUErrorWritingCharacteristicFailed: 94 | return @"DFUErrorWritingCharacteristicFailed"; 95 | case DFUErrorRemoteSecureDFUExtendedError: 96 | return @"DFUErrorRemoteSecureDFUExtendedError"; 97 | case DFUErrorRemoteSecureDFUInvalidObject: 98 | return @"DFUErrorRemoteSecureDFUInvalidObject"; 99 | case DFUErrorRemoteLegacyDFUOperationFailed: 100 | return @"DFUErrorRemoteLegacyDFUOperationFailed"; 101 | case DFUErrorRemoteSecureDFUOperationFailed: 102 | return @"DFUErrorRemoteSecureDFUOperationFailed"; 103 | case DFUErrorRemoteSecureDFUUnsupportedType: 104 | return @"DFUErrorRemoteSecureDFUUnsupportedType"; 105 | case DFUErrorRemoteLegacyDFUDataExceedsLimit: 106 | return @"DFUErrorRemoteLegacyDFUDataExceedsLimit"; 107 | case DFUErrorRemoteSecureDFUInvalidParameter: 108 | return @"DFUErrorRemoteSecureDFUInvalidParameter"; 109 | case DFUErrorRemoteSecureDFUSignatureMismatch: 110 | return @"DFUErrorRemoteSecureDFUSignatureMismatch"; 111 | case DFUErrorRemoteSecureDFUOpCodeNotSupported: 112 | return @"DFUErrorRemoteSecureDFUOpCodeNotSupported"; 113 | case DFUErrorRemoteButtonlessDFUOperationFailed: 114 | return @"DFUErrorRemoteButtonlessDFUOperationFailed"; 115 | case DFUErrorRemoteSecureDFUInsufficientResources: 116 | return @"DFUErrorRemoteSecureDFUInsufficientResources"; 117 | case DFUErrorRemoteSecureDFUOperationNotPermitted: 118 | return @"DFUErrorRemoteSecureDFUOperationNotPermitted"; 119 | case DFUErrorRemoteButtonlessDFUOpCodeNotSupported: 120 | return @"DFUErrorRemoteButtonlessDFUOpCodeNotSupported"; 121 | case DFUErrorRemoteExperimentalButtonlessDFUSuccess: 122 | return @"DFUErrorRemoteExperimentalButtonlessDFUSuccess"; 123 | case DFUErrorRemoteExperimentalButtonlessDFUOperationFailed: 124 | return @"DFUErrorRemoteExperimentalButtonlessDFUOperationFailed"; 125 | case DFUErrorRemoteExperimentalButtonlessDFUOpCodeNotSupported: 126 | return @"DFUErrorRemoteExperimentalButtonlessDFUOpCodeNotSupported"; 127 | default: 128 | return @"UNKNOWN_ERROR"; 129 | } 130 | } 131 | 132 | - (void)dfuStateDidChangeTo:(enum DFUState)state 133 | { 134 | NSDictionary * evtBody = @{@"deviceAddress": self.deviceAddress, 135 | @"state": [self stateDescription:state],}; 136 | 137 | [self sendEventWithName:DFUStateChangedEvent body:evtBody]; 138 | 139 | if (state == DFUStateCompleted) { 140 | if (onDFUComplete) { 141 | onDFUComplete(); 142 | } 143 | NSDictionary * resolveBody = @{@"deviceAddress": self.deviceAddress,}; 144 | 145 | self.resolve(resolveBody); 146 | } 147 | } 148 | 149 | - (void) dfuError:(enum DFUError)error 150 | didOccurWithMessage:(NSString * _Nonnull)message 151 | { 152 | if (onDFUError) { 153 | onDFUError(); 154 | } 155 | 156 | NSDictionary * evtBody = @{@"deviceAddress": self.deviceAddress, 157 | @"state": @"DFU_FAILED",}; 158 | 159 | [self sendEventWithName:DFUStateChangedEvent body:evtBody]; 160 | 161 | self.reject([self errorDescription:error], message, nil); 162 | } 163 | 164 | - (void)dfuProgressDidChangeFor:(NSInteger)part 165 | outOf:(NSInteger)totalParts 166 | to:(NSInteger)progress 167 | currentSpeedBytesPerSecond:(double)currentSpeedBytesPerSecond 168 | avgSpeedBytesPerSecond:(double)avgSpeedBytesPerSecond 169 | { 170 | NSDictionary * evtBody = @{@"deviceAddress": self.deviceAddress, 171 | @"currentPart": [NSNumber numberWithInteger:part], 172 | @"partsTotal": [NSNumber numberWithInteger:totalParts], 173 | @"percent": [NSNumber numberWithInteger:progress], 174 | @"speed": [NSNumber numberWithDouble:currentSpeedBytesPerSecond], 175 | @"avgSpeed": [NSNumber numberWithDouble:avgSpeedBytesPerSecond],}; 176 | 177 | [self sendEventWithName:DFUProgressEvent body:evtBody]; 178 | } 179 | 180 | - (void)logWith:(enum LogLevel)level message:(NSString * _Nonnull)message 181 | { 182 | NSLog(@"logWith: %ld message: '%@'", (long)level, message); 183 | } 184 | 185 | RCT_EXPORT_METHOD(startDFU:(NSString *)deviceAddress 186 | deviceName:(NSString *)deviceName 187 | filePath:(NSString *)filePath 188 | alternativeAdvertisingNameEnabled:(BOOL *)alternativeAdvertisingNameEnabled 189 | resolver:(RCTPromiseResolveBlock)resolve 190 | rejecter:(RCTPromiseRejectBlock)reject) 191 | { 192 | self.deviceAddress = deviceAddress; 193 | self.resolve = resolve; 194 | self.reject = reject; 195 | 196 | if (!getCentralManager) { 197 | reject(@"nil_central_manager_getter", @"Attempted to start DFU without central manager getter", nil); 198 | } else { 199 | CBCentralManager * centralManager = getCentralManager(); 200 | 201 | if (!centralManager) { 202 | reject(@"nil_central_manager", @"Call to getCentralManager returned nil", nil); 203 | } else if (!deviceAddress) { 204 | reject(@"nil_device_address", @"Attempted to start DFU with nil deviceAddress", nil); 205 | } else if (!filePath) { 206 | reject(@"nil_file_path", @"Attempted to start DFU with nil filePath", nil); 207 | } else { 208 | NSUUID * uuid = [[NSUUID alloc] initWithUUIDString:deviceAddress]; 209 | 210 | NSArray * peripherals = [centralManager retrievePeripheralsWithIdentifiers:@[uuid]]; 211 | 212 | if ([peripherals count] != 1) { 213 | reject(@"unable_to_find_device", @"Could not find device with deviceAddress", nil); 214 | } else { 215 | CBPeripheral * peripheral = [peripherals objectAtIndex:0]; 216 | 217 | NSURL * url = [NSURL URLWithString:filePath]; 218 | 219 | DFUFirmware * firmware = [[DFUFirmware alloc] initWithUrlToZipFile:url]; 220 | 221 | DFUServiceInitiator * initiator = [[[DFUServiceInitiator alloc] 222 | initWithCentralManager:centralManager 223 | target:peripheral] 224 | withFirmware:firmware]; 225 | 226 | initiator.logger = self; 227 | initiator.delegate = self; 228 | initiator.progressDelegate = self; 229 | initiator.alternativeAdvertisingNameEnabled = alternativeAdvertisingNameEnabled; 230 | 231 | DFUServiceController * controller = [initiator start]; 232 | } 233 | } 234 | } 235 | } 236 | 237 | + (void)setCentralManagerGetter:(CBCentralManager * (^)())getter 238 | { 239 | getCentralManager = getter; 240 | } 241 | 242 | + (void)setOnDFUComplete:(void (^)())onComplete 243 | { 244 | onDFUComplete = onComplete; 245 | } 246 | 247 | + (void)setOnDFUError:(void (^)())onError 248 | { 249 | onDFUError = onError; 250 | } 251 | 252 | @end 253 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-nordic-dfu [![npm version](https://badge.fury.io/js/react-native-nordic-dfu.svg)](https://badge.fury.io/js/react-native-nordic-dfu) [![CircleCI](https://circleci.com/gh/Pilloxa/react-native-nordic-dfu.svg?style=svg)](https://circleci.com/gh/Pilloxa/react-native-nordic-dfu) [![Known Vulnerabilities](https://snyk.io/test/github/pilloxa/react-native-nordic-dfu/badge.svg)](https://snyk.io/test/github/pilloxa/react-native-nordic-dfu) 2 | 3 | > ⚠️ Warning! This library is no longer actively maintained. For a more up to date version check out: [Salt-PepperEngineering/react-native-nordic-dfu](https://github.com/Salt-PepperEngineering/react-native-nordic-dfu) 4 | 5 | This library allows you to do a Device Firmware Update (DFU) of your nrf51 or 6 | nrf52 chip from Nordic Semiconductor. It works for both iOS and Android. 7 | 8 | For more info about the DFU process, see: [Resources](#resources) 9 | 10 | ## Installation 11 | 12 | Install and link the NPM package per usual with 13 | 14 | ```bash 15 | npm install --save react-native-nordic-dfu 16 | ``` 17 | 18 | or 19 | 20 | ```bash 21 | yarn add react-native-nordic-dfu 22 | ``` 23 | 24 | For React Native below 60.0 version 25 | 26 | ```bash 27 | react-native link react-native-nordic-dfu 28 | ``` 29 | 30 | ### Minimum requirements 31 | 32 | This project has been verified to work with the following dependencies, though other versions may work as well. 33 | 34 | | Dependency | Version | 35 | | ------------ | ------- | 36 | | React Native | 0.59.4 | 37 | | XCode | 10.2 | 38 | | Swift | 5.0 | 39 | | CocoaPods | 1.6.1 | 40 | | Gradle | 5.3.1 | 41 | 42 | ### iOS 43 | 44 | The iOS version of this library has native dependencies that need to be installed via `CocoaPods`, which is currently the only supported method for installing this library. (PR's for alternative installation methods are welcome!) 45 | 46 | Previous versions supported manual linking, but this was prone to errors every time a new version of XCode and/or Swift was released, which is why this support was dropped. If you've previously installed this library manually, you'll want to remove the old installation and replace it with CocoaPods. 47 | 48 | #### CocoaPods 49 | 50 | On your project directory; 51 | 52 | ```bash 53 | cd ios && pod install 54 | ``` 55 | 56 | If your React Native version below 0.60 or any problem occures on pod command, you can try these steps; 57 | 58 | Add the following to your `Podfile` 59 | 60 | ```ruby 61 | target "YourApp" do 62 | 63 | ... 64 | pod "react-native-nordic-dfu", path: "../node_modules/react-native-nordic-dfu" 65 | ... 66 | 67 | end 68 | ``` 69 | 70 | and in the same folder as the Podfile run 71 | 72 | ```bash 73 | pod install 74 | ``` 75 | 76 | Since there's native Swift dependencies you need to set which Swift version your project complies with. If you haven't already done this, open up your project with XCode and add a User-Defined setting under Build Settings: `SWIFT_VERSION = `. 77 | 78 | If your React Native version is higher than 0.60, probably it's already there. 79 | 80 | #### Bluetooth integration 81 | 82 | This library needs access to an instance of `CBCentralManager`, which you most likely will have instantiated already if you're using Bluetooth for other purposes than DFU in your project. 83 | 84 | To integrate with your existing Bluetooth setup, call `[RNNordicDfu setCentralManagerGetter:<...>]` with a block argument that returns your `CBCentralManager` instance. 85 | 86 | If you want control over the `CBCentralManager` instance after the DFU process is done you might need to provide the `onDFUComplete` and `onDFUError` callbacks to transfer back delegate control. 87 | 88 | Example code; 89 | 90 | ```swift 91 | ... 92 | ... 93 | #import "RNNordicDfu.h" 94 | #import "BleManager.h" 95 | 96 | @implementation AppDelegate 97 | 98 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ 99 | ... 100 | ... 101 | 102 | [RNNordicDfu setCentralManagerGetter:^() { 103 | return [BleManager getCentralManager]; 104 | }]; 105 | 106 | // Reset manager delegate since the Nordic DFU lib "steals" control over it 107 | [RNNordicDfu setOnDFUComplete:^() { 108 | NSLog(@"onDFUComplete"); 109 | CBCentralManager * manager = [BleManager getCentralManager]; 110 | manager.delegate = [BleManager getInstance]; 111 | }]; 112 | 113 | [RNNordicDfu setOnDFUError:^() { 114 | NSLog(@"onDFUError"); 115 | CBCentralManager * manager = [BleManager getCentralManager]; 116 | manager.delegate = [BleManager getInstance]; 117 | }]; 118 | 119 | return YES; 120 | } 121 | 122 | ``` 123 | 124 | You can find them aslo in example project. 125 | 126 | On iOS side this library requires to BleManager module which that [react-native-ble-manager](https://github.com/innoveit/react-native-ble-manager) provides. 127 | 128 | It required because; 129 | 130 | - You need `BleManager.h` module on AppDelegate file for integration. 131 | - You should call `BleManager.start()` (for once) before the trigger a DFU process on iOS or you will get error like [this issue](https://github.com/Pilloxa/react-native-nordic-dfu/issues/82). 132 | 133 | ### Android 134 | 135 | Android requires that you have `FOREGROUND_SERVICE` permissions. 136 | You will need the following in your AndroidManifest.xml 137 | 138 | ``` 139 | 140 | ``` 141 | 142 | ## API 143 | 144 | 145 | 146 | ### startDFU 147 | 148 | Starts the DFU process 149 | 150 | Observe: The peripheral must have been discovered by the native BLE side so that the 151 | bluetooth stack knows about it. This library will not do a scan but only 152 | the actual connect and then the transfer. See the example project to see how it can be 153 | done in React Native. 154 | 155 | **Parameters** 156 | 157 | - `obj` **[Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object)** 158 | - `obj.deviceAddress` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The `identifier`\* of the device that should be updated 159 | - `obj.deviceName` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The name of the device in the update notification (optional, default `null`) 160 | - `obj.filePath` **[string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String)** The file system path to the zip-file used for updating 161 | - `obj.alternativeAdvertisingNameEnabled` **[boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Send unique name to device before it is switched into bootloader mode (iOS only) - defaults to `true` 162 | 163 | \* `identifier` — MAC address (Android) / UUID (iOS) 164 | 165 | **Examples** 166 | 167 | ```javascript 168 | import { NordicDFU, DFUEmitter } from "react-native-nordic-dfu"; 169 | 170 | NordicDFU.startDFU({ 171 | deviceAddress: "C3:53:C0:39:2F:99", 172 | deviceName: "Pilloxa Pillbox", 173 | filePath: "/data/user/0/com.nordicdfuexample/files/RNFetchBlobTmp4of.zip", 174 | }) 175 | .then((res) => console.log("Transfer done:", res)) 176 | .catch(console.log); 177 | ``` 178 | 179 | Returns **[Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)** A promise that resolves or rejects with the `deviceAddress` in the return value 180 | 181 | ### DFUEmitter 182 | 183 | Event emitter for DFU state and progress events 184 | 185 | **Examples** 186 | 187 | ```javascript 188 | import { NordicDFU, DFUEmitter } from "react-native-nordic-dfu"; 189 | 190 | DFUEmitter.addListener( 191 | "DFUProgress", 192 | ({ percent, currentPart, partsTotal, avgSpeed, speed }) => { 193 | console.log("DFU progress: " + percent + "%"); 194 | } 195 | ); 196 | 197 | DFUEmitter.addListener("DFUStateChanged", ({ state }) => { 198 | console.log("DFU State:", state); 199 | }); 200 | ``` 201 | 202 | ## Selecting firmware file from local storage 203 | 204 | If your user will select the firmware file from local storage you should keep on mind some issues; 205 | 206 | You can use [react-native-document-picker](https://github.com/Elyx0/react-native-document-picker) library for file selecting process. 207 | 208 | ### On iOS 209 | 210 | You should select file type as `public.archive` or you will get null type error as like [this issue](https://github.com/Pilloxa/react-native-nordic-dfu/issues/100) 211 | 212 | ```js 213 | DocumentPicker.pick({ type: "public.archive" }); 214 | ``` 215 | 216 | If your device getting disconnect after enable DFU, you should set `false` value to `alternativeAdvertisingNameEnabled` prop while starting DFU. 217 | 218 | ```js 219 | NordicDFU.startDFU({ 220 | deviceAddress: "XXXXXXXX-XXXX-XXXX-XXXX-XX", 221 | filePath: firmwareFile.uri, 222 | alternativeAdvertisingNameEnabled: false, 223 | }); 224 | ``` 225 | 226 | ### On Android 227 | 228 | Some Android versions directly selecting file may can cause errors. If you get any file error you should copy it to your local storage. Like cache directory. 229 | 230 | You can use [react-native-fs](https://github.com/itinance/react-native-fs) for copying file. 231 | 232 | ```js 233 | const firmwareFile = await DocumentPicker.pick({ type: DocumentPicker.types.zip }) 234 | const destination = RNFS.CachesDirectoryPath + "/firmwareFile.zip"); 235 | 236 | await RNFS.copyFile(formatFile.uri, destination); 237 | 238 | NordicDFU.startDFU({ deviceAddress: "XX:XX:XX:XX:XX:XX", filePath: destination }) 239 | ``` 240 | 241 | If you getting disconnect error sometimes while starting DFU process, you should connect the device before start it. 242 | 243 | ## Example project 244 | 245 | Navigate to `example/` and run 246 | 247 | ```bash 248 | npm install 249 | ``` 250 | 251 | Run the iOS project with 252 | 253 | ```bash 254 | react-native run-ios 255 | ``` 256 | 257 | and the Android project with 258 | 259 | ```bash 260 | react-native run-android 261 | ``` 262 | 263 | ## Development 264 | 265 | PR's are always welcome! 266 | 267 | ## Resources 268 | 269 | - [DFU Introduction](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/examples_ble_dfu.html?cp=6_0_0_4_3_1 "BLE Bootloader/DFU") 270 | - [Secure DFU Introduction](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v12.0.0/ble_sdk_app_dfu_bootloader.html?cp=4_0_0_4_3_1 "BLE Secure DFU Bootloader") 271 | - [How to create init packet](https://github.com/NordicSemiconductor/Android-nRF-Connect/tree/master/init%20packet%20handling "Init packet handling") 272 | - [nRF51 Development Kit (DK)](http://www.nordicsemi.com/eng/Products/nRF51-DK "nRF51 DK") (compatible with Arduino Uno Revision 3) 273 | - [nRF52 Development Kit (DK)](http://www.nordicsemi.com/eng/Products/Bluetooth-Smart-Bluetooth-low-energy/nRF52-DK "nRF52 DK") (compatible with Arduino Uno Revision 3) 274 | 275 | ## Sponsored by 276 | 277 | [![pilloxa](https://pilloxa.com/images/pilloxa-round-logo.svg)](https://pilloxa.com) 278 | -------------------------------------------------------------------------------- /example/ios/NordicDFUExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 11 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 12 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13 | 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 14 | AFBD98CE42EE4D292DE30278 /* Pods_NordicDFUExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6478854F2D98962939006428 /* Pods_NordicDFUExample.framework */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | A53E61CC1F45E7370001EB4F /* Embed Frameworks */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 2147483647; 21 | dstPath = ""; 22 | dstSubfolderSpec = 10; 23 | files = ( 24 | ); 25 | name = "Embed Frameworks"; 26 | runOnlyForDeploymentPostprocessing = 0; 27 | }; 28 | /* End PBXCopyFilesBuildPhase section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; }; 32 | 13B07F961A680F5B00A75B9A /* NordicDFUExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NordicDFUExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = NordicDFUExample/AppDelegate.h; sourceTree = ""; }; 34 | 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = NordicDFUExample/AppDelegate.m; sourceTree = ""; }; 35 | 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 36 | 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = NordicDFUExample/Images.xcassets; sourceTree = ""; }; 37 | 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = NordicDFUExample/Info.plist; sourceTree = ""; }; 38 | 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = NordicDFUExample/main.m; sourceTree = ""; }; 39 | 23DB7F518D38EFB05D9954C8 /* Pods-NordicDFUExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NordicDFUExample.release.xcconfig"; path = "Target Support Files/Pods-NordicDFUExample/Pods-NordicDFUExample.release.xcconfig"; sourceTree = ""; }; 40 | 6478854F2D98962939006428 /* Pods_NordicDFUExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NordicDFUExample.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | FA2EA6D15548AF2E9141F82E /* Pods-NordicDFUExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NordicDFUExample.debug.xcconfig"; path = "Target Support Files/Pods-NordicDFUExample/Pods-NordicDFUExample.debug.xcconfig"; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 13B07F8C1A680F5B00A75B9A /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | AFBD98CE42EE4D292DE30278 /* Pods_NordicDFUExample.framework in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXFrameworksBuildPhase section */ 54 | 55 | /* Begin PBXGroup section */ 56 | 13B07FAE1A68108700A75B9A /* NordicDFUExample */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 008F07F21AC5B25A0029DE68 /* main.jsbundle */, 60 | 13B07FAF1A68108700A75B9A /* AppDelegate.h */, 61 | 13B07FB01A68108700A75B9A /* AppDelegate.m */, 62 | 13B07FB51A68108700A75B9A /* Images.xcassets */, 63 | 13B07FB61A68108700A75B9A /* Info.plist */, 64 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */, 65 | 13B07FB71A68108700A75B9A /* main.m */, 66 | ); 67 | name = NordicDFUExample; 68 | sourceTree = ""; 69 | }; 70 | 3A4D31ACCE1F1F6885CF77A1 /* Pods */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | FA2EA6D15548AF2E9141F82E /* Pods-NordicDFUExample.debug.xcconfig */, 74 | 23DB7F518D38EFB05D9954C8 /* Pods-NordicDFUExample.release.xcconfig */, 75 | ); 76 | path = Pods; 77 | sourceTree = ""; 78 | }; 79 | 83CBB9F61A601CBA00E9B192 = { 80 | isa = PBXGroup; 81 | children = ( 82 | 13B07FAE1A68108700A75B9A /* NordicDFUExample */, 83 | 83CBBA001A601CBA00E9B192 /* Products */, 84 | 3A4D31ACCE1F1F6885CF77A1 /* Pods */, 85 | CD8C38820690DE8FB4BF3E99 /* Frameworks */, 86 | ); 87 | indentWidth = 2; 88 | sourceTree = ""; 89 | tabWidth = 2; 90 | }; 91 | 83CBBA001A601CBA00E9B192 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 13B07F961A680F5B00A75B9A /* NordicDFUExample.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | CD8C38820690DE8FB4BF3E99 /* Frameworks */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 6478854F2D98962939006428 /* Pods_NordicDFUExample.framework */, 103 | ); 104 | name = Frameworks; 105 | sourceTree = ""; 106 | }; 107 | /* End PBXGroup section */ 108 | 109 | /* Begin PBXNativeTarget section */ 110 | 13B07F861A680F5B00A75B9A /* NordicDFUExample */ = { 111 | isa = PBXNativeTarget; 112 | buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NordicDFUExample" */; 113 | buildPhases = ( 114 | 554227AE062BEDCA14FCD59E /* [CP] Check Pods Manifest.lock */, 115 | 13B07F871A680F5B00A75B9A /* Sources */, 116 | 13B07F8C1A680F5B00A75B9A /* Frameworks */, 117 | 13B07F8E1A680F5B00A75B9A /* Resources */, 118 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 119 | A53E61CC1F45E7370001EB4F /* Embed Frameworks */, 120 | 4B0AD483234F0DC3E0F75BEF /* [CP] Embed Pods Frameworks */, 121 | ); 122 | buildRules = ( 123 | ); 124 | dependencies = ( 125 | ); 126 | name = NordicDFUExample; 127 | productName = "Hello World"; 128 | productReference = 13B07F961A680F5B00A75B9A /* NordicDFUExample.app */; 129 | productType = "com.apple.product-type.application"; 130 | }; 131 | /* End PBXNativeTarget section */ 132 | 133 | /* Begin PBXProject section */ 134 | 83CBB9F71A601CBA00E9B192 /* Project object */ = { 135 | isa = PBXProject; 136 | attributes = { 137 | LastUpgradeCheck = 0830; 138 | ORGANIZATIONNAME = Facebook; 139 | TargetAttributes = { 140 | 13B07F861A680F5B00A75B9A = { 141 | DevelopmentTeam = X8M4Z7CAY5; 142 | }; 143 | }; 144 | }; 145 | buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "NordicDFUExample" */; 146 | compatibilityVersion = "Xcode 3.2"; 147 | developmentRegion = English; 148 | hasScannedForEncodings = 0; 149 | knownRegions = ( 150 | English, 151 | en, 152 | Base, 153 | ); 154 | mainGroup = 83CBB9F61A601CBA00E9B192; 155 | productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; 156 | projectDirPath = ""; 157 | projectRoot = ""; 158 | targets = ( 159 | 13B07F861A680F5B00A75B9A /* NordicDFUExample */, 160 | ); 161 | }; 162 | /* End PBXProject section */ 163 | 164 | /* Begin PBXResourcesBuildPhase section */ 165 | 13B07F8E1A680F5B00A75B9A /* Resources */ = { 166 | isa = PBXResourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */, 170 | 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXResourcesBuildPhase section */ 175 | 176 | /* Begin PBXShellScriptBuildPhase section */ 177 | 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = { 178 | isa = PBXShellScriptBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | ); 182 | inputPaths = ( 183 | ); 184 | name = "Bundle React Native code and images"; 185 | outputPaths = ( 186 | ); 187 | runOnlyForDeploymentPostprocessing = 0; 188 | shellPath = /bin/sh; 189 | shellScript = "export NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n"; 190 | }; 191 | 4B0AD483234F0DC3E0F75BEF /* [CP] Embed Pods Frameworks */ = { 192 | isa = PBXShellScriptBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | ); 196 | inputFileListPaths = ( 197 | ); 198 | inputPaths = ( 199 | "${PODS_ROOT}/Target Support Files/Pods-NordicDFUExample/Pods-NordicDFUExample-frameworks.sh", 200 | "${BUILT_PRODUCTS_DIR}/DoubleConversion/DoubleConversion.framework", 201 | "${BUILT_PRODUCTS_DIR}/Folly/folly.framework", 202 | "${BUILT_PRODUCTS_DIR}/React/React.framework", 203 | "${BUILT_PRODUCTS_DIR}/ZIPFoundation/ZIPFoundation.framework", 204 | "${BUILT_PRODUCTS_DIR}/glog/glog.framework", 205 | "${BUILT_PRODUCTS_DIR}/iOSDFULibrary/iOSDFULibrary.framework", 206 | "${BUILT_PRODUCTS_DIR}/react-native-ble-manager/react_native_ble_manager.framework", 207 | "${BUILT_PRODUCTS_DIR}/react-native-nordic-dfu/react_native_nordic_dfu.framework", 208 | "${BUILT_PRODUCTS_DIR}/rn-fetch-blob/rn_fetch_blob.framework", 209 | "${BUILT_PRODUCTS_DIR}/yoga/yoga.framework", 210 | ); 211 | name = "[CP] Embed Pods Frameworks"; 212 | outputFileListPaths = ( 213 | ); 214 | outputPaths = ( 215 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DoubleConversion.framework", 216 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/folly.framework", 217 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/React.framework", 218 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ZIPFoundation.framework", 219 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/glog.framework", 220 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/iOSDFULibrary.framework", 221 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_ble_manager.framework", 222 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/react_native_nordic_dfu.framework", 223 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/rn_fetch_blob.framework", 224 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/yoga.framework", 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | shellPath = /bin/sh; 228 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NordicDFUExample/Pods-NordicDFUExample-frameworks.sh\"\n"; 229 | showEnvVarsInLog = 0; 230 | }; 231 | 554227AE062BEDCA14FCD59E /* [CP] Check Pods Manifest.lock */ = { 232 | isa = PBXShellScriptBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | ); 236 | inputFileListPaths = ( 237 | ); 238 | inputPaths = ( 239 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 240 | "${PODS_ROOT}/Manifest.lock", 241 | ); 242 | name = "[CP] Check Pods Manifest.lock"; 243 | outputFileListPaths = ( 244 | ); 245 | outputPaths = ( 246 | "$(DERIVED_FILE_DIR)/Pods-NordicDFUExample-checkManifestLockResult.txt", 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | shellPath = /bin/sh; 250 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 251 | showEnvVarsInLog = 0; 252 | }; 253 | /* End PBXShellScriptBuildPhase section */ 254 | 255 | /* Begin PBXSourcesBuildPhase section */ 256 | 13B07F871A680F5B00A75B9A /* Sources */ = { 257 | isa = PBXSourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */, 261 | 13B07FC11A68108700A75B9A /* main.m in Sources */, 262 | ); 263 | runOnlyForDeploymentPostprocessing = 0; 264 | }; 265 | /* End PBXSourcesBuildPhase section */ 266 | 267 | /* Begin PBXVariantGroup section */ 268 | 13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = { 269 | isa = PBXVariantGroup; 270 | children = ( 271 | 13B07FB21A68108700A75B9A /* Base */, 272 | ); 273 | name = LaunchScreen.xib; 274 | path = NordicDFUExample; 275 | sourceTree = ""; 276 | }; 277 | /* End PBXVariantGroup section */ 278 | 279 | /* Begin XCBuildConfiguration section */ 280 | 13B07F941A680F5B00A75B9A /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | baseConfigurationReference = FA2EA6D15548AF2E9141F82E /* Pods-NordicDFUExample.debug.xcconfig */; 283 | buildSettings = { 284 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 285 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 286 | CURRENT_PROJECT_VERSION = 1; 287 | DEAD_CODE_STRIPPING = NO; 288 | DEVELOPMENT_TEAM = X8M4Z7CAY5; 289 | ENABLE_BITCODE = NO; 290 | INFOPLIST_FILE = NordicDFUExample/Info.plist; 291 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 292 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 293 | ONLY_ACTIVE_ARCH = YES; 294 | OTHER_LDFLAGS = ( 295 | "$(inherited)", 296 | "-ObjC", 297 | "-lc++", 298 | ); 299 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 300 | PRODUCT_NAME = NordicDFUExample; 301 | VALID_ARCHS = "arm64 armv7 armv7s"; 302 | VERSIONING_SYSTEM = "apple-generic"; 303 | }; 304 | name = Debug; 305 | }; 306 | 13B07F951A680F5B00A75B9A /* Release */ = { 307 | isa = XCBuildConfiguration; 308 | baseConfigurationReference = 23DB7F518D38EFB05D9954C8 /* Pods-NordicDFUExample.release.xcconfig */; 309 | buildSettings = { 310 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 311 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 312 | CURRENT_PROJECT_VERSION = 1; 313 | DEVELOPMENT_TEAM = X8M4Z7CAY5; 314 | ENABLE_BITCODE = NO; 315 | INFOPLIST_FILE = NordicDFUExample/Info.plist; 316 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 317 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 318 | ONLY_ACTIVE_ARCH = NO; 319 | OTHER_LDFLAGS = ( 320 | "$(inherited)", 321 | "-ObjC", 322 | "-lc++", 323 | ); 324 | PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; 325 | PRODUCT_NAME = NordicDFUExample; 326 | VALID_ARCHS = "arm64 armv7 armv7s"; 327 | VERSIONING_SYSTEM = "apple-generic"; 328 | }; 329 | name = Release; 330 | }; 331 | 83CBBA201A601CBA00E9B192 /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 335 | ALWAYS_SEARCH_USER_PATHS = NO; 336 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 337 | CLANG_CXX_LIBRARY = "libc++"; 338 | CLANG_ENABLE_MODULES = YES; 339 | CLANG_ENABLE_OBJC_ARC = YES; 340 | CLANG_WARN_BOOL_CONVERSION = YES; 341 | CLANG_WARN_CONSTANT_CONVERSION = YES; 342 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 343 | CLANG_WARN_EMPTY_BODY = YES; 344 | CLANG_WARN_ENUM_CONVERSION = YES; 345 | CLANG_WARN_INFINITE_RECURSION = YES; 346 | CLANG_WARN_INT_CONVERSION = YES; 347 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 348 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 349 | CLANG_WARN_UNREACHABLE_CODE = YES; 350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 351 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 352 | COPY_PHASE_STRIP = NO; 353 | ENABLE_STRICT_OBJC_MSGSEND = YES; 354 | ENABLE_TESTABILITY = YES; 355 | GCC_C_LANGUAGE_STANDARD = gnu99; 356 | GCC_DYNAMIC_NO_PIC = NO; 357 | GCC_NO_COMMON_BLOCKS = YES; 358 | GCC_OPTIMIZATION_LEVEL = 0; 359 | GCC_PREPROCESSOR_DEFINITIONS = ( 360 | "DEBUG=1", 361 | "$(inherited)", 362 | ); 363 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 364 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 365 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 366 | GCC_WARN_UNDECLARED_SELECTOR = YES; 367 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 368 | GCC_WARN_UNUSED_FUNCTION = YES; 369 | GCC_WARN_UNUSED_VARIABLE = YES; 370 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 371 | MTL_ENABLE_DEBUG_INFO = YES; 372 | ONLY_ACTIVE_ARCH = YES; 373 | SDKROOT = iphoneos; 374 | SWIFT_VERSION = 5; 375 | }; 376 | name = Debug; 377 | }; 378 | 83CBBA211A601CBA00E9B192 /* Release */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 382 | ALWAYS_SEARCH_USER_PATHS = NO; 383 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 384 | CLANG_CXX_LIBRARY = "libc++"; 385 | CLANG_ENABLE_MODULES = YES; 386 | CLANG_ENABLE_OBJC_ARC = YES; 387 | CLANG_WARN_BOOL_CONVERSION = YES; 388 | CLANG_WARN_CONSTANT_CONVERSION = YES; 389 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 390 | CLANG_WARN_EMPTY_BODY = YES; 391 | CLANG_WARN_ENUM_CONVERSION = YES; 392 | CLANG_WARN_INFINITE_RECURSION = YES; 393 | CLANG_WARN_INT_CONVERSION = YES; 394 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 395 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = YES; 400 | ENABLE_NS_ASSERTIONS = NO; 401 | ENABLE_STRICT_OBJC_MSGSEND = YES; 402 | GCC_C_LANGUAGE_STANDARD = gnu99; 403 | GCC_NO_COMMON_BLOCKS = YES; 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 411 | MTL_ENABLE_DEBUG_INFO = NO; 412 | SDKROOT = iphoneos; 413 | SWIFT_VERSION = 5; 414 | VALIDATE_PRODUCT = YES; 415 | }; 416 | name = Release; 417 | }; 418 | /* End XCBuildConfiguration section */ 419 | 420 | /* Begin XCConfigurationList section */ 421 | 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "NordicDFUExample" */ = { 422 | isa = XCConfigurationList; 423 | buildConfigurations = ( 424 | 13B07F941A680F5B00A75B9A /* Debug */, 425 | 13B07F951A680F5B00A75B9A /* Release */, 426 | ); 427 | defaultConfigurationIsVisible = 0; 428 | defaultConfigurationName = Release; 429 | }; 430 | 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "NordicDFUExample" */ = { 431 | isa = XCConfigurationList; 432 | buildConfigurations = ( 433 | 83CBBA201A601CBA00E9B192 /* Debug */, 434 | 83CBBA211A601CBA00E9B192 /* Release */, 435 | ); 436 | defaultConfigurationIsVisible = 0; 437 | defaultConfigurationName = Release; 438 | }; 439 | /* End XCConfigurationList section */ 440 | }; 441 | rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */; 442 | } 443 | --------------------------------------------------------------------------------