Bluetooth and WIFI Printing for Android

69,325

Solution 1

Starting with Android 4.4 you can print documents from a device to a hardware printer via wifi.

Android apps can now print any type of content over Wi-Fi or cloud-hosted services such as Google Cloud Print. In print-enabled apps, users can discover available printers, change paper sizes, choose specific pages to print, and print almost any kind of document, image, or file.

A brief example of how to start the printing process:

private void doPrint() {
    PrintManager printManager = (PrintManager) getActivity().getSystemService(Context.PRINT_SERVICE);
    printManager.print("My document", new CustomPrintDocumentAdapter(getActivity()), null);
}

where CustomPrintDocumentAdapter extends PrintDocumentAdapter.

More information is available on Android Developers.

Solution 2

Printing via Bluetooth on Android is not possible as of now (as per my knowledge), as Android does not support Bluetooth 'Profiles', such as BPP (Basic Printing Profile), HCRP (Hardcopy Replacement Profile), BIP (Basic Imaging Profile) etc. which are the common profiles used with Bluetooth Printing. Ref. this to know about Printing BT profiles.

Currently, Android supports OPP (Object Push Profile) which is used to send files over Bluetooth.

To have printing bluetooth profiles implemented within the Bluetooth Stack for Android, you can refer Sybase-iAnywhere-Blue-SDK-for-Android, which provides an SDK to add this functionality to the existing BT stack implementation on Android.

For Wifi printing, there are many apps on the market that allows you to print various documents and images from your Android phone. See PrinterShare for one such app. For Wifi printing, you can use any printer that you can connect over ethernet (LAN).

Also check out printers that are 'Google Cloud Print' enabled, which uses the cloud to print to a printer connected anywhere in the world, that supports this protocol. This is quite new in the market, but something that will definitely gain traction over the coming years. Check out Cloud print app here. and faq here.

Hope this helps take out a few questions off your list.

Solution 3

Sorry I don't have knowledge about printing using bluetooth devices.. But, I did some research about printing using wifi and posted that code in GitHub, You can refer to that if needed.. Android-wifi-print - GitHub

This is the flow of that prototype.

  1. checks connectivity.
  2. If connected in WiFi.. am storing that WiFi configuration.
  3. Now checking whether I already have printer's information (WiFi configuration of WiFi printer) is available or not. If available, I'll scan and get list of WiFi ScanResults and connects to that else.. It'll showing list of WiFi and clicking on that, user will connect to printer and stores that WiFi configuration for future printing jobs.
  4. After print job completes, I'm connecting to my previous WiFi or Mobile data connection.
  5. Now going back to 2nd step.
  6. If user connected in Mobile data, I'm just enabling WiFi and following 3rd step.
  7. After Print job completes, I'm just disabling WiFi. so that, We'll be connected back to Mobile data connection. (That is android default).

Below class will take care of all printing jobs in that prototype.

PrintUtility.class

public class PrintUtility implements Observer {

    private static final int TIME_OUT = 10000;
    private static final int CONNECTION_TIME_OUT = 5000;

    private Activity mActivity;
    private Fragment mFragment = null;

    private WifiConfiguration mPrinterConfiguration;
    private WifiConfiguration mOldWifiConfiguration;
    private WifiManager mWifiManager;
    private WifiScanner mWifiScanner;
    private List<ScanResult> mScanResults = new ArrayList<ScanResult>();

    private PrintManager mPrintManager;
    private List<PrintJob> mPrintJobs;
    private PrintJob mCurrentPrintJob;

    private File pdfFile;
    private String externalStorageDirectory;

    private Handler mPrintStartHandler = new Handler();
    private Handler mPrintCompleteHandler = new Handler();
    private Handler mWifiConnectHandler = new Handler();
    private String connectionInfo;

    private boolean isMobileDataConnection = false;

    private PrintCompleteService mPrintCompleteService;

    //    Observer pattern
    private Observable mObservable;


    public PrintUtility(Activity mActivity, WifiManager mWifiManager, WifiScanner mWifiScanner) {
        this.mActivity = mActivity;
        this.mWifiManager = mWifiManager;
        this.mWifiScanner = mWifiScanner;
        mPrintCompleteService = (PrintCompleteService) mActivity;
        mObservable = ObservableSingleton.getInstance();
        mObservable.attach(this);
    }

    public PrintUtility(Activity mActivity, Fragment mFragment, WifiManager mWifiManager, WifiScanner mWifiScanner) {
        this.mActivity = mActivity;
        this.mFragment = mFragment;
        this.mWifiManager = mWifiManager;
        this.mWifiScanner = mWifiScanner;
        mPrintCompleteService = (PrintCompleteService) mFragment;
        mObservable = ObservableSingleton.getInstance();
        mObservable.attach(this);
    }

    public void downloadAndPrint(String fileUrl, final String fileName) {

        new FileDownloader(mActivity, fileUrl, fileName) {
            @Override
            protected void onPostExecute(Boolean result) {

                if (!result) {
                    mObservable.notifyObserver(true);
                } else {

                    // print flow will come here.

                    try {
                        externalStorageDirectory = Environment.getExternalStorageDirectory().toString();
                        File folder = new File(externalStorageDirectory, Constants.CONTROLLER_PDF_FOLDER);
                        pdfFile = new File(folder, fileName);
                    } catch (Exception e) {
                        mObservable.notifyObserver(true);
                        e.printStackTrace();
                    }

                    print(pdfFile);

                }

            }
        }.execute("");
    }

    public void print(final File pdfFile) {

        this.pdfFile = pdfFile;

        // check connectivity info -> mobile or wifi.
        connectionInfo = Util.connectionInfo(mActivity);

        if (connectionInfo.equalsIgnoreCase(Constants.CONTROLLER_MOBILE)) {
            // follow mobile flow.
            isMobileDataConnection = true;

            if (mWifiManager.isWifiEnabled() == false) {
                mWifiManager.setWifiEnabled(true);
            }

            mWifiManager.startScan();
            setScanResults(mWifiScanner.getScanResults());

            printerConfiguration();

        } else if (connectionInfo.equalsIgnoreCase(Constants.CONTROLLER_WIFI)) {
            // follow wifi flow..

            // this will get current wifiInfo and store it in shared preference.
            Util.storeCurrentWiFiConfiguration(mActivity);

            printerConfiguration();

        } else {
            mObservable.notifyObserver(true);
        }

    }

    private void printerConfiguration() {

        // check printer detail is available or not.
        mPrinterConfiguration = Util.getWifiConfiguration(mActivity, Constants.CONTROLLER_PRINTER);

        if (mPrinterConfiguration == null) {
            // printer configuration is not available.
            // display list of wifi available in an activity

            showWifiListActivity(Constants.REQUEST_CODE_PRINTER);

        } else {
            // get list of wifi available. if printer configuration available then connect it.
            // else.. show list of available wifi nearby.

            boolean isPrinterAvailable = false;

            // scans nearby wifi..
            mWifiManager.startScan();
            setScanResults(mWifiScanner.getScanResults());


            // checks this wifi in scan result list..
            for (int i = 0; i < mScanResults.size(); i++) {
                if (mPrinterConfiguration.SSID.equals("\"" + mScanResults.get(i).SSID + "\"")) {
                    isPrinterAvailable = true;
                    break;
                }
            }

            if (isPrinterAvailable) {

                // connect to printer wifi and show print settings dialog and continue with print flow.
                connectToWifi(mPrinterConfiguration);

                // prints document.
                doPrint();

            } else {
                showWifiListActivity(Constants.REQUEST_CODE_PRINTER);
            }

        }
    }

    private void showWifiListActivity(int requestCode) {
        Intent iWifi = new Intent(mActivity, WifiListActivity.class);
        mActivity.startActivityForResult(iWifi, requestCode);
    }

    private void connectToWifi(WifiConfiguration mWifiConfiguration) {
        mWifiManager.enableNetwork(mWifiConfiguration.networkId, true);
    }

    public void doPrint() {

        try {
            // it is taking some time to connect to printer.. so i used handler.. and waiting for its status.
            mPrintStartHandler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    mPrintStartHandler.postDelayed(this, TIME_OUT);

                    if (mPrinterConfiguration.status == WifiConfiguration.Status.CURRENT) {
                        if (mWifiManager.getConnectionInfo().getSupplicantState() == SupplicantState.COMPLETED) {

                            if (Util.computePDFPageCount(pdfFile) > 0) {
                                printDocument(pdfFile);
                            } else {

                                AlertDialog.Builder alert = new AlertDialog.Builder(mActivity);

                                alert.setMessage("Can't print, Page count is zero.");

                                alert.setNeutralButton("OK", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int i) {
                                        dialog.dismiss();
                                        switchConnection();
                                    }
                                });

                                alert.show();
                            }
                        }
                        mPrintStartHandler.removeCallbacksAndMessages(null);
                    } else {
                        Toast.makeText(mActivity, "Failed to connect to printer!.", Toast.LENGTH_LONG).show();
                        switchConnection();
                        mPrintStartHandler.removeCallbacksAndMessages(null);
                    }
                }
            }, TIME_OUT);
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(mActivity, "Failed to connect to printer!.", Toast.LENGTH_LONG).show();
            switchConnection();
        }
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void printDocument(File pdfFile) {

        mPrintManager = (PrintManager) mActivity.getSystemService(Context.PRINT_SERVICE);

        String jobName = mActivity.getResources().getString(R.string.app_name) + " Document";

        mCurrentPrintJob = mPrintManager.print(jobName, new PrintServicesAdapter(mActivity, mFragment, pdfFile), null);
    }


    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void completePrintJob() {
        mPrintJobs = mPrintManager.getPrintJobs();

        mPrintCompleteHandler.postDelayed(new Runnable() {
            @Override
            public void run() {

                mPrintCompleteHandler.postDelayed(this, CONNECTION_TIME_OUT);

                if (mCurrentPrintJob.getInfo().getState() == PrintJobInfo.STATE_COMPLETED) {

                    // remove that PrintJob from PrintManager.
                    for (int i = 0; i < mPrintJobs.size(); i++) {
                        if (mPrintJobs.get(i).getId() == mCurrentPrintJob.getId()) {
                            mPrintJobs.remove(i);
                        }
                    }

                    // switching back to previous connection..
                    switchConnection();

                    // stops handler..
                    mPrintCompleteHandler.removeCallbacksAndMessages(null);
                } else if (mCurrentPrintJob.getInfo().getState() == PrintJobInfo.STATE_FAILED) {
                    switchConnection();
                    Toast.makeText(mActivity, "Print Failed!", Toast.LENGTH_LONG).show();
                    mPrintCompleteHandler.removeCallbacksAndMessages(null);
                } else if (mCurrentPrintJob.getInfo().getState() == PrintJobInfo.STATE_CANCELED) {
                    switchConnection();
                    Toast.makeText(mActivity, "Print Cancelled!", Toast.LENGTH_LONG).show();
                    mPrintCompleteHandler.removeCallbacksAndMessages(null);
                }

            }
        }, CONNECTION_TIME_OUT);
    }

    public void switchConnection() {
        try {
            if (!isMobileDataConnection) {

                mOldWifiConfiguration = Util.getWifiConfiguration(mActivity, Constants.CONTROLLER_WIFI);

                // get list of wifi available. if wifi configuration available then connect it.
                // else.. show list of available wifi nearby.
                boolean isWifiAvailable = false;

                // scans nearby wifi.
                mWifiManager.startScan();
                setScanResults(mWifiScanner.getScanResults());

                // checks this wifi in scan result list.
                for (int i = 0; i < mScanResults.size(); i++) {
                    if (mOldWifiConfiguration.SSID.equals("\"" + mScanResults.get(i).SSID + "\"")) {
                        isWifiAvailable = true;
                        break;
                    }
                }

                if (isWifiAvailable) {

                    // connect to printer wifi and show print settings dialog and continue with print flow.
                    connectToWifi(mOldWifiConfiguration);

                    mWifiConnectHandler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            mWifiConnectHandler.postDelayed(this, TIME_OUT);
                            if (mOldWifiConfiguration.status == WifiConfiguration.Status.CURRENT) {
                                if (mWifiManager.getConnectionInfo().getSupplicantState() == SupplicantState.COMPLETED) {

                                    try {
                                        mObservable.notifyObserver(true);
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }

                                    mWifiConnectHandler.removeCallbacksAndMessages(null);
                                }
                            }
                        }
                    }, TIME_OUT);

                } else {
                    showWifiListActivity(Constants.REQUEST_CODE_WIFI);
                }
            } else {
                mWifiManager.setWifiEnabled(false);
                mObservable.notifyObserver(true);
            }
        } catch (Exception e) {
            mObservable.notifyObserver(true);
            e.printStackTrace();
        }
    }

    public void getPrinterConfigAndPrint() {
        mPrinterConfiguration = Util.getWifiConfiguration(mActivity, Constants.CONTROLLER_PRINTER);
        doPrint();
    }

    public void setScanResults(List<ScanResult> scanResults) {
        this.mScanResults = scanResults;
    }

    public void onPrintCancelled() {
        switchConnection();
    }

    @Override
    public void update() {
        mObservable.detach(this);
    }

    @Override
    public void updateObserver(boolean bool) {

    }

    @Override
    public void updateObserverProgress(int percentage) {

    }

}

With the help of following links I have created this.

If you want to print your file just call print(file)

If you want to download a file and print that, call downloadAndPrint(fileUrl, fileName)

Solution 4

The only printing i have been able to integrate is for the Bixolon SPP-R200. They have a decent SDK available and is pretty easy to find. I'm looking for 8 1/2 x 11 bluetooth capabilities but an sdk for something like that seems to be a pretty tall order right now

Solution 5

Star Micronics has an SDK for Android printing via Bluetooth (as well as wifi/ethernet and USB). You can download it here: http://www.starmicronics.com/support/SDKDocumentation.aspx.

As mentioned above, you can't print natively at this point in time so your options are either a specific printer API or a 3rd party printing app.

In my experience, it's best to use an API and not an external application. The biggest reason is you get total control over printer behavior. It's easy to implement if the API is built intelligently. Using an 3rd party app is limiting because you can't customize your print outs the way you want to.

The Star SDK I linked you to has a really nice sample app that lets you test and customize a lot of printer functions to see them in action. Each function is documented in the source code. The commands and their parameters are also available in the app itself as a quick on screen reference which is convenient. On top of all that, it's well documented.

If you choose this way, you can send plain text to the printer along with commands. The API handles converting the data into what the printer can understand.

Share:
69,325

Related videos on Youtube

Gábor Lipták
Author by

Gábor Lipták

I make a living from having some knowledge about two digits. The zero and the one.

Updated on July 10, 2020

Comments

  • Gábor Lipták
    Gábor Lipták almost 4 years

    We would need a portable printer (handheld, it is important) that can connect to android phone via bluetooth or wifi.

    What I know currently:

    • No standard printing SDK available for Android this time
    • There is a non official SDK called iPrint SDK. Have any of you tried it through wifi or bluetooth? Does it work?
    • Printershare also claims to be programmaticly available. It would be ok for me to pay the one time fee $5 for it per phone. It has a lot of supported formats. Have you tried it with any handheld device? I asked them about the list of supported bluetooth printers (since it has a menu item "search for BT printer"), but they did not answered.

    What I need to know above the already asked:

    • How do you print from your android app?
    • What kind of printer do you use?
    • Is it planned in the standard android SDK to include printing? What is the roadmap? Is it available now as Beta or something?
    • If we somehow (i dont think so) build own solution for printing via bluetooth, can you recommend standards and protocols to check and learn?
  • Gábor Lipták
    Gábor Lipták over 13 years
    Thank you for the answer. Some time later I will accept, if nobody else answers. Until then +1.
  • Roy Samuel
    Roy Samuel almost 13 years
    check out stackoverflow.com/questions/1421326/bluetooth-on-android/… for more info regarding the Bluetooth Roadmap...
  • Gábor Lipták
    Gábor Lipták almost 13 years
    Thanks for explanatory answer. I appreciate it.
  • Jayabal
    Jayabal over 12 years
    Hi TML, where can I get SDK for Bixolon SPP-R200 printer. pls help.
  • AgentKnopf
    AgentKnopf about 12 years
    @baya write directly to the bixolon support and request it. The Bixolon's support email is: [email protected] . although the email is a German one, as far as I know those guys answer in English too.
  • Ravi
    Ravi almost 11 years
    @LtH please send me the same code to integrate with application ,in my case it is crashing
  • Noufal
    Noufal about 10 years
    @LtH can this applicable for all printers stackoverflow.com/questions/23557722/…
  • Noufal
    Noufal about 10 years
    @ Gunnar Karlsson what to do when it comes in lower android version like ginger bread.please can you suggest any thing ?stackoverflow.com/questions/23557722/…
  • Jon B
    Jon B about 9 years
    The SDK link is broken. Anyone got a fix for that? It's not clear from the Zebra site of this is still available. Is this it? zebra.com/us/en/products/software/barcode-printers/link-os/…
  • Artyom
    Artyom almost 7 years
    It isn't true, that printing via Bluetooth is impossible, at least because PrinterShare app can do it.
  • Sharath
    Sharath almost 7 years
    Hello, Thanks for the solution that you given. I found that there are many printers available in the market. Could you please tell me, if the same solution can work for all the universal printers? Waiting for the reply.
  • saeed khalafinejad
    saeed khalafinejad almost 5 years
    You can easily print via Bluetooth. Most of printers come with a sample and/or SDK which help you to print content (text and image) to the Bluetooth. However if u target SDK 28 Google imposed some limitation in Bluetooth communication (I would say Android 9 has a bug in Bluetooth management and they will solve it)
  • Vishali
    Vishali over 3 years
    @SureshCS50 this solution is not working for me.i have downloaded your github project from the link which you have posted but not working