0

Is it possible to use ZQ511 printer with React Native?

https://developer.zebra.com/blog/develop-react-native-printing-app-android-ios-link-os-sdk

I did all the steps in this link but the app cannot find the printer.

Does anyone have experience with this or can help? What should I do?

Thanks.

Print.js

import React, { Component } from 'react';
import { ActivityIndicator, Platform } from 'react-native';
import { StyleSheet, Button, TouchableOpacity, Text, View, Alert } from 'react-native';
import ZSDKModule from './ZSDKModule.js';


class App extends Component {
   
  state = { printers: [] }; // Starting with an empty list for the listview

  isDiscovering = false; // Hide or reveal the spinner
  buttonTitle = 'Click to Discover Bluetooth Printers';

  printTestLabel = (printer) => {
    alert(`A test label is printed on ${printer.name}`);

    if (Platform.OS === 'ios') {
      ZSDKModule.zsdkWriteBluetooth(printer.name, ''); // Use friendlyName on iOS

    } else {
      var mac_sn = printer.name.split(', '); // e.g. ["AC:3F:A4:BE:90:93","XXZEJ173500341"]
      console.log(mac_sn);
      var macAddress = mac_sn[0];
      var friendlyName = mac_sn[1];
      ZSDKModule.zsdkWriteBluetooth(macAddress, ''); // Use MAC address on Android
    }
  }

  discoverPrinters = () => {
    console.log("1");
    // First, clear the listview
    var printersArray = [];
    
    this.setState({printers: printersArray});
    this.isDiscovering = true;
    this.buttonTitle = 'Scanning for Zebra Printers ...';
    console.log("2");
    ZSDKModule.zsdkPrinterDiscoveryBluetooth(
      
       // The callback to be called by the native module after Bluetooth discovery finishes.
       (error, discoveredPrinters) => {
        console.log("3");
        this.isDiscovering = false; // Disable the spinner
        this.buttonTitle = 'Click to Discover Bluetooth Printers';
        console.log('discoveredPrinters: '+discoveredPrinters);
        if (error) {
          console.error(`Error found! ${error}`);
        }

        console.log(`Discovered printers are: ${discoveredPrinters}`);

        // Parse the JSON string
        var printersJson = JSON.parse(discoveredPrinters);

        var printersArray = []; // Discovered printer array for listview

        // Traverse the JSON object of printers to compose an array for the listview
        if (Platform.OS === 'ios') {
          // Cannot get printer's MAC address on iOS. Only the friendlyName
          for (var i = 0; i < printersJson.length; i++) {
            printersArray.push({id: i, name: `${printersJson[i].friendlyName}`});
          }
        } else {
          // We have both MAC address and the friendlyName on Android
          for (var i = 0; i < printersJson.length; i++) {
            printersArray.push({id: i, name: `${printersJson[i].address}` + `, ` + `${printersJson[i].friendlyName}`});
          }
        }

        console.log(printersArray);

        // Update the listview
        this.setState({printers: printersArray});

      }
    );
  }

  render() {
    return (
      <View style={{marginTop: 50}}>
        <Text style={styles.headline}>ZSDK RCT Native Module DevDemo</Text>

        <Button
          title={this.buttonTitle}
          color='#841584'
          disabled={this.isDiscovering}
          onPress={this.discoverPrinters}
        />

        {
          this.state.printers.map((printer, index) => (
            <TouchableOpacity
              key = {printer.id}
              style = {styles.container}
              onPress = {() => this.printTestLabel(printer)}>
              <Text style = {styles.text}>
                {printer.name}
              </Text>
            </TouchableOpacity>
          ))
        }

        <View style={{marginTop: 150}}>
          {this.isDiscovering && <ActivityIndicator size='large' color='#0000ff' />}
        </View>
      </View>
    )
  }
}

export default App

const styles = StyleSheet.create({
  container: {
    marginTop: 3,
    padding: 10,
    backgroundColor: '#d9f9b1',
    alignItems: 'center',
    justifyContent: 'center',
  },

  text: {
      color: '#4f603c'
  },

  headline: {
    textAlign: 'center',
    fontWeight: 'bold',
    fontSize: 17,
    marginTop: 0,
  },

});

ZSDKModule.js

import { NativeModules } from 'react-native';
const { ZSDKModule } = NativeModules;
export default ZSDKModule;

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="com.symbol.datawedge.api.ACTION" />
<uses-permission android:name="com.symbol.datawedge.api.RESULT_ACTION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>



    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:roundIcon="@mipmap/ic_launcher_round"
      android:allowBackup="false"
      android:theme="@style/AppTheme">
      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
        android:launchMode="singleTask"
        android:windowSoftInputMode="adjustResize"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
      </activity>
    </application>
</manifest>

MainApplication.java

package com.sistapmobileapp;

import android.app.Application;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
import com.facebook.react.defaults.DefaultReactNativeHost;
import com.facebook.soloader.SoLoader;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost =
      new DefaultReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          packages.add(new ZSDKModulePackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }

        @Override
        protected boolean isNewArchEnabled() {
          return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
        }

        @Override
        protected Boolean isHermesEnabled() {
          return BuildConfig.IS_HERMES_ENABLED;
        }
      };

  @Override
  public ReactNativeHost getReactNativeHost() {
    return mReactNativeHost;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    SoLoader.init(this, /* native exopackage */ false);
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      // If you opted-in for the New Architecture, we load the native entry point for this app.
      DefaultNewArchitectureEntryPoint.load();
    }
    ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }
}

ZSDKModulePackage.java

package com.sistapmobileapp;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ZSDKModulePackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();

        modules.add(new ZSDKModule(reactContext));

        return modules;
    }

}

ZSDKModule.java

package com.sistapmobileapp;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.zebra.sdk.comm.BluetoothConnection;
import com.zebra.sdk.comm.Connection;
import com.zebra.sdk.comm.ConnectionException;
import com.zebra.sdk.printer.PrinterLanguage;
import com.zebra.sdk.printer.ZebraPrinter;
import com.zebra.sdk.printer.ZebraPrinterFactory;
import com.zebra.sdk.printer.ZebraPrinterLanguageUnknownException;
import com.facebook.react.bridge.Callback;
import com.zebra.sdk.printer.discovery.BluetoothDiscoverer;
import com.zebra.sdk.printer.discovery.DiscoveredPrinter;
import com.zebra.sdk.printer.discovery.DiscoveredPrinterBluetooth;
import com.zebra.sdk.printer.discovery.DiscoveryHandler;

import java.io.Console;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;


public class ZSDKModule extends ReactContextBaseJavaModule {

    ZSDKModule(ReactApplicationContext context) {
        super(context);
    }

    
    @Override
    public String getName() {
        return "ZSDKModule";
    }

    @ReactMethod
    public void zsdkWriteBluetooth(String macAddress, String zpl) {
        Log.d("ZSDKModule", "Going to write via Bluetooth with MAC address: " + macAddress
                + " and zpl: " + zpl);

        Connection printerConnection = null;
        ZebraPrinter printer = null;

        printerConnection = new BluetoothConnection(macAddress);

        try {
            printerConnection.open();

            if (printerConnection.isConnected()) {
                printer = ZebraPrinterFactory.getInstance(printerConnection);
                PrinterLanguage printerLanguage = printer.getPrinterControlLanguage();
                byte[] testLabel = getTestLabel(printerLanguage);
                printerConnection.write(testLabel);
            }
        } catch (ConnectionException e) {
            // Do something
        } catch (ZebraPrinterLanguageUnknownException e) {
            // Do something
        } finally {
            try {
                if (printerConnection != null) {
                    printerConnection.close();
                }
            } catch (ConnectionException ex) {
                // Do something
            }
        }
    }

    
    private byte[] getTestLabel(PrinterLanguage printerLanguage) {
        byte[] testLabel = null;
        if (printerLanguage == PrinterLanguage.ZPL) {
            testLabel = "^XA^FO17,16^GB379,371,8^FS^FT65,255^A0N,135,134^FDTEST^FS^XZ".getBytes();
        } else if (printerLanguage == PrinterLanguage.CPCL || printerLanguage == PrinterLanguage.LINE_PRINT) {
            String cpclConfigLabel = "! 0 200 200 406 1\r\n" + "ON-FEED IGNORE\r\n" + "BOX 20 20 380 380 8\r\n" + "T 0 6 137 177 TEST\r\n" + "PRINT\r\n";
            testLabel = cpclConfigLabel.getBytes();
        }
        return testLabel;
    }

    @ReactMethod
    public void zsdkPrinterDiscoveryBluetooth(Callback callback) {
        try {
            BluetoothDiscoverer.findPrinters(getReactApplicationContext(), new DiscoveryResult(callback));
            
        
        } catch (ConnectionException e) {
            // Do something
        } finally {
            // Do something
        }
    }

    // Implementation to DiscoveryHandler
    public class DiscoveryResult implements DiscoveryHandler {

        protected Callback callback = null;
        protected ArrayList<Map<String, String>> foundPrinterList;

        public DiscoveryResult(Callback callback) {
            super();
            this.callback = callback;
            foundPrinterList = new ArrayList<Map<String, String>>();
        }

        @Override
        public void foundPrinter(final DiscoveredPrinter printer) {
            DiscoveredPrinter dp = printer;
            Map<String, String> foundPrinter = new HashMap<>();
            foundPrinter.put("address", printer.address);
            foundPrinter.put("friendlyName", ((DiscoveredPrinterBluetooth) printer).friendlyName);
            foundPrinterList.add(foundPrinter);
        }

        @Override
        public void discoveryFinished() {

            // Convert the foundPrinterList into JSON string
            List<JSONObject> jsonObj = new ArrayList<JSONObject>();

            for(Map<String, String> data : foundPrinterList) {
                jsonObj.add(new JSONObject(data));
            }

            JSONArray foundPrinterJson = new JSONArray(jsonObj);

            Log.d("ZSDKModule", "Found printers are: " + foundPrinterJson.toString());

            // Invoke the callback in React Native
            callback.invoke(null, foundPrinterJson.toString());
        }

        @Override
        public void discoveryError(String message) {
            // To do
        }
    }
}
3
  • On which android version are you running your app? Im sure you are missing to ask permissions to use location data at runtime: developer.zebra.com/content/… Commented Jan 10, 2024 at 9:22
  • I add this line but nothing happend ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.BLUETOOTH}, 2); Commented Jan 10, 2024 at 11:01
  • Where did you add this? is this even called? Did you check the response event? Commented Jan 10, 2024 at 12:04

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.