├── .buckconfig ├── .bundle └── config ├── .eslintrc.js ├── .flowconfig ├── .gitignore ├── .prettierrc.js ├── .ruby-version ├── .watchmanconfig ├── App.js ├── Gemfile ├── Gemfile.lock ├── ItemList.js ├── SamplePrint.js ├── __tests__ └── App-test.js ├── android ├── app │ ├── BUCK │ ├── build.gradle │ ├── build_defs.bzl │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── bluetoothprinter │ │ │ └── ReactNativeFlipper.java │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── bluetoothprinter │ │ │ ├── MainActivity.java │ │ │ ├── MainApplication.java │ │ │ └── newarchitecture │ │ │ ├── MainApplicationReactNativeHost.java │ │ │ ├── components │ │ │ └── MainComponentsRegistry.java │ │ │ └── modules │ │ │ └── MainApplicationTurboModuleManagerDelegate.java │ │ ├── jni │ │ ├── Android.mk │ │ ├── MainApplicationModuleProvider.cpp │ │ ├── MainApplicationModuleProvider.h │ │ ├── MainApplicationTurboModuleManagerDelegate.cpp │ │ ├── MainApplicationTurboModuleManagerDelegate.h │ │ ├── MainComponentsRegistry.cpp │ │ ├── MainComponentsRegistry.h │ │ └── OnLoad.cpp │ │ └── res │ │ ├── drawable │ │ └── rn_edit_text_material.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── babel.config.js ├── dummy-logo.js ├── index.js ├── ios ├── Podfile ├── Podfile.lock ├── bluetoothPrinter.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ └── bluetoothPrinter.xcscheme ├── bluetoothPrinter.xcworkspace │ └── contents.xcworkspacedata ├── bluetoothPrinter │ ├── AppDelegate.h │ ├── AppDelegate.mm │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── LaunchScreen.storyboard │ └── main.m └── bluetoothPrinterTests │ ├── Info.plist │ └── bluetoothPrinterTests.m ├── metro.config.js ├── package.json ├── styles.js └── yarn.lock /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; 5 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; Flow doesn't support platforms 12 | .*/Libraries/Utilities/LoadingView.js 13 | 14 | .*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ 15 | 16 | [untyped] 17 | .*/node_modules/@react-native-community/cli/.*/.* 18 | 19 | [include] 20 | 21 | [libs] 22 | node_modules/react-native/interface.js 23 | node_modules/react-native/flow/ 24 | 25 | [options] 26 | emoji=true 27 | 28 | exact_by_default=true 29 | 30 | format.bracket_spacing=false 31 | 32 | module.file_ext=.js 33 | module.file_ext=.json 34 | module.file_ext=.ios.js 35 | 36 | munge_underscores=true 37 | 38 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 39 | 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\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 40 | 41 | suppress_type=$FlowIssue 42 | suppress_type=$FlowFixMe 43 | suppress_type=$FlowFixMeProps 44 | suppress_type=$FlowFixMeState 45 | 46 | [lints] 47 | sketchy-null-number=warn 48 | sketchy-null-mixed=warn 49 | sketchy-number=warn 50 | untyped-type-import=warn 51 | nonstrict-import=warn 52 | deprecated-type=warn 53 | unsafe-getters-setters=warn 54 | unnecessary-invariant=warn 55 | signature-verification-failure=warn 56 | 57 | [strict] 58 | deprecated-type 59 | nonstrict-import 60 | sketchy-null 61 | unclear-type 62 | unsafe-getters-setters 63 | untyped-import 64 | untyped-type-import 65 | 66 | [version] 67 | ^0.170.0 68 | -------------------------------------------------------------------------------- /.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 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | *.hprof 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 | !debug.keystore 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://docs.fastlane.tools/best-practices/source-control/ 51 | 52 | */fastlane/report.xml 53 | */fastlane/Preview.html 54 | */fastlane/screenshots 55 | 56 | # Bundle artifact 57 | *.jsbundle 58 | 59 | # Ruby / CocoaPods 60 | /ios/Pods/ 61 | /vendor/bundle/ 62 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | arrowParens: 'avoid', 3 | bracketSameLine: true, 4 | bracketSpacing: false, 5 | singleQuote: true, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.4 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /App.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useCallback } from 'react'; 2 | import { 3 | ActivityIndicator, 4 | DeviceEventEmitter, 5 | NativeEventEmitter, 6 | PermissionsAndroid, 7 | Platform, 8 | ScrollView, 9 | Text, 10 | ToastAndroid, 11 | View, 12 | Button, 13 | } from 'react-native'; 14 | import { BluetoothManager } from 'react-native-bluetooth-escpos-printer'; 15 | import { PERMISSIONS, requestMultiple, RESULTS } from 'react-native-permissions'; 16 | import ItemList from './ItemList'; 17 | import SamplePrint from './SamplePrint'; 18 | import { styles } from './styles'; 19 | 20 | const App = () => { 21 | const [pairedDevices, setPairedDevices] = useState([]); 22 | const [foundDs, setFoundDs] = useState([]); 23 | const [bleOpend, setBleOpend] = useState(false); 24 | const [loading, setLoading] = useState(true); 25 | const [name, setName] = useState(''); 26 | const [boundAddress, setBoundAddress] = useState(''); 27 | 28 | useEffect(() => { 29 | BluetoothManager.isBluetoothEnabled().then( 30 | enabled => { 31 | setBleOpend(Boolean(enabled)); 32 | setLoading(false); 33 | }, 34 | err => { 35 | err; 36 | }, 37 | ); 38 | 39 | if (Platform.OS === 'ios') { 40 | let bluetoothManagerEmitter = new NativeEventEmitter(BluetoothManager); 41 | bluetoothManagerEmitter.addListener(BluetoothManager.EVENT_DEVICE_ALREADY_PAIRED, rsp => { 42 | deviceAlreadPaired(rsp); 43 | }); 44 | bluetoothManagerEmitter.addListener(BluetoothManager.EVENT_DEVICE_FOUND, rsp => { 45 | deviceFoundEvent(rsp); 46 | }); 47 | bluetoothManagerEmitter.addListener(BluetoothManager.EVENT_CONNECTION_LOST, () => { 48 | setName(''); 49 | setBoundAddress(''); 50 | }); 51 | } else if (Platform.OS === 'android') { 52 | DeviceEventEmitter.addListener(BluetoothManager.EVENT_DEVICE_ALREADY_PAIRED, rsp => { 53 | deviceAlreadPaired(rsp); 54 | }); 55 | DeviceEventEmitter.addListener(BluetoothManager.EVENT_DEVICE_FOUND, rsp => { 56 | deviceFoundEvent(rsp); 57 | }); 58 | DeviceEventEmitter.addListener(BluetoothManager.EVENT_CONNECTION_LOST, () => { 59 | setName(''); 60 | setBoundAddress(''); 61 | }); 62 | DeviceEventEmitter.addListener(BluetoothManager.EVENT_BLUETOOTH_NOT_SUPPORT, () => { 63 | ToastAndroid.show('Device Not Support Bluetooth !', ToastAndroid.LONG); 64 | }); 65 | } 66 | if (pairedDevices.length < 1) { 67 | scan(); 68 | } 69 | }, [boundAddress, deviceAlreadPaired, deviceFoundEvent, pairedDevices, scan]); 70 | 71 | const deviceAlreadPaired = useCallback( 72 | rsp => { 73 | var ds = null; 74 | if (typeof rsp.devices === 'object') { 75 | ds = rsp.devices; 76 | } else { 77 | try { 78 | ds = JSON.parse(rsp.devices); 79 | } catch (e) {} 80 | } 81 | if (ds && ds.length) { 82 | let pared = pairedDevices; 83 | if (pared.length < 1) { 84 | pared = pared.concat(ds || []); 85 | } 86 | setPairedDevices(pared); 87 | } 88 | }, 89 | [pairedDevices], 90 | ); 91 | 92 | const deviceFoundEvent = useCallback( 93 | rsp => { 94 | var r = null; 95 | try { 96 | if (typeof rsp.device === 'object') { 97 | r = rsp.device; 98 | } else { 99 | r = JSON.parse(rsp.device); 100 | } 101 | } catch (e) { 102 | // ignore error 103 | } 104 | 105 | if (r) { 106 | let found = foundDs || []; 107 | if (found.findIndex) { 108 | let duplicated = found.findIndex(function (x) { 109 | return x.address == r.address; 110 | }); 111 | if (duplicated == -1) { 112 | found.push(r); 113 | setFoundDs(found); 114 | } 115 | } 116 | } 117 | }, 118 | [foundDs], 119 | ); 120 | 121 | const connect = row => { 122 | setLoading(true); 123 | BluetoothManager.connect(row.address).then( 124 | s => { 125 | setLoading(false); 126 | setBoundAddress(row.address); 127 | setName(row.name || 'UNKNOWN'); 128 | }, 129 | e => { 130 | setLoading(false); 131 | alert(e); 132 | }, 133 | ); 134 | }; 135 | 136 | const unPair = address => { 137 | setLoading(true); 138 | BluetoothManager.unpaire(address).then( 139 | s => { 140 | setLoading(false); 141 | setBoundAddress(''); 142 | setName(''); 143 | }, 144 | e => { 145 | setLoading(false); 146 | alert(e); 147 | }, 148 | ); 149 | }; 150 | 151 | const scanDevices = useCallback(() => { 152 | setLoading(true); 153 | BluetoothManager.scanDevices().then( 154 | s => { 155 | // const pairedDevices = s.paired; 156 | var found = s.found; 157 | try { 158 | found = JSON.parse(found); //@FIX_it: the parse action too weired.. 159 | } catch (e) { 160 | //ignore 161 | } 162 | var fds = foundDs; 163 | if (found && found.length) { 164 | fds = found; 165 | } 166 | setFoundDs(fds); 167 | setLoading(false); 168 | }, 169 | er => { 170 | setLoading(false); 171 | // ignore 172 | }, 173 | ); 174 | }, [foundDs]); 175 | 176 | const scan = useCallback(() => { 177 | try { 178 | async function blueTooth() { 179 | const permissions = { 180 | title: 'HSD bluetooth meminta izin untuk mengakses bluetooth', 181 | message: 'HSD bluetooth memerlukan akses ke bluetooth untuk proses koneksi ke bluetooth printer', 182 | buttonNeutral: 'Lain Waktu', 183 | buttonNegative: 'Tidak', 184 | buttonPositive: 'Boleh', 185 | }; 186 | 187 | const bluetoothConnectGranted = await PermissionsAndroid.request( 188 | PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT, 189 | permissions, 190 | ); 191 | if (bluetoothConnectGranted === PermissionsAndroid.RESULTS.GRANTED) { 192 | const bluetoothScanGranted = await PermissionsAndroid.request( 193 | PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN, 194 | permissions, 195 | ); 196 | if (bluetoothScanGranted === PermissionsAndroid.RESULTS.GRANTED) { 197 | scanDevices(); 198 | } 199 | } else { 200 | // ignore akses ditolak 201 | } 202 | } 203 | blueTooth(); 204 | } catch (err) { 205 | console.warn(err); 206 | } 207 | }, [scanDevices]); 208 | 209 | const scanBluetoothDevice = async () => { 210 | setLoading(true); 211 | try { 212 | const request = await requestMultiple([ 213 | PERMISSIONS.ANDROID.BLUETOOTH_CONNECT, 214 | PERMISSIONS.ANDROID.BLUETOOTH_SCAN, 215 | PERMISSIONS.ANDROID.ACCESS_FINE_LOCATION, 216 | ]); 217 | 218 | if (request['android.permission.ACCESS_FINE_LOCATION'] === RESULTS.GRANTED) { 219 | scanDevices(); 220 | setLoading(false); 221 | } else { 222 | setLoading(false); 223 | } 224 | } catch (err) { 225 | setLoading(false); 226 | } 227 | }; 228 | 229 | return ( 230 | 231 | 232 | 233 | Bluetooth {bleOpend ? 'Aktif' : 'Non Aktif'} 234 | 235 | 236 | {!bleOpend && Mohon aktifkan bluetooth anda} 237 | Printer yang terhubung ke aplikasi: 238 | {boundAddress.length > 0 && ( 239 | unPair(boundAddress)} 243 | actionText="Putus" 244 | color="#E9493F" 245 | /> 246 | )} 247 | {boundAddress.length < 1 && ( 248 | Belum ada printer yang terhubung 249 | )} 250 | Bluetooth yang terhubung ke HP ini: 251 | {loading ? : null} 252 | 253 | {pairedDevices.map((item, index) => { 254 | return ( 255 | connect(item)} 258 | label={item.name} 259 | value={item.address} 260 | connected={item.address === boundAddress} 261 | actionText="Hubungkan" 262 | color="#00BCD4" 263 | /> 264 | ); 265 | })} 266 | 267 | 268 |