7个回答

19

Android 4.4开始,您可以通过wifi从设备打印文档到硬件打印机。

现在,Android应用程序可以通过Wi-Fi或云托管服务(如Google Cloud Print)打印任何类型的内容。在启用打印功能的应用程序中,用户可以查找可用的打印机、更改纸张大小、选择要打印的特定页面,并打印几乎任何种类的文档、图像或文件。

以下是如何开始打印过程的简短示例:

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

其中CustomPrintDocumentAdapter扩展了PrintDocumentAdapter

有关更多信息,请访问Android开发者网站。


2
@Gunnar Karlsson,如果在较低的Android版本(如姜饼)中出现问题,该怎么办?请问您有什么建议吗?https://dev59.com/43_aa4cB1Zd3GeqP4ISg - Noufal

15

截至目前(据我所知),Android不支持蓝牙“配置文件”,例如BPP(基本打印配置文件)、HCRP(硬拷贝替代配置文件)、BIP(基本成像配置文件)等,这些是与蓝牙打印一起使用的常见配置文件。因此,目前无法通过蓝牙在Android上进行打印。请参考this了解有关打印BT配置文件的信息。

目前,Android支持OPP(对象推送配置文件),用于通过蓝牙发送文件。

要在Android的蓝牙堆栈中实现打印蓝牙配置文件,您可以参考Sybase-iAnywhere-Blue-SDK-for-Android,该SDK提供了向现有BT堆栈实现添加此功能的方法。

对于Wifi打印,市场上有许多应用程序可让您从Android手机打印各种文档和图像。其中一个应用程序是PrinterShare。对于Wifi打印,您可以使用任何可以通过以太网(LAN)连接的打印机。

此外,还可以查看支持“Google Cloud Print”功能的打印机,它使用云端打印到任何支持该协议的连接世界各地的打印机。这在市场上还比较新,但肯定会在未来几年中获得更多关注。请查看云打印应用程序常见问题解答
希望这能帮助您解决一些问题。

请查看https://dev59.com/-nM_5IYBdhLWcg3wUxjF#1422113,了解有关蓝牙路线图的更多信息... - Roy Samuel
感谢您详细的解答,我非常感激。 - Gábor Lipták
这并不是真的,通过蓝牙打印并非不可能,至少PrinterShare应用可以实现。 - Artyom
您可以轻松通过蓝牙打印。大多数打印机都配备了示例和/或SDK,可帮助您将内容(文本和图像)打印到蓝牙上。但是,如果您的目标SDK为28,则Google在蓝牙通信方面施加了一些限制(我会说Android 9在蓝牙管理方面存在错误,他们将解决它)。 - saeed khalafinejad

8

抱歉,我不了解使用蓝牙设备进行打印的知识。但是,我在GitHub上做了一些关于使用wifi进行打印的研究,并发布了相关代码。如果需要,您可以参考一下。Android-wifi-print - GitHub

这是那个原型的流程。

  1. 检查连接性。
  2. 如果连接到WiFi,我会存储该WiFi配置。
  3. 现在检查是否已经有打印机的信息(WiFi打印机的WiFi配置)可用。如果可用,我将扫描并获取WiFi ScanResults列表并连接到其中一个,否则它将显示WiFi列表,用户点击其中一个即可连接到打印机并为未来的打印作业存储该WiFi配置。
  4. 打印作业完成后,我会连接回我的先前WiFi或移动数据连接。
  5. 现在回到第2步。
  6. 如果用户连接到移动数据,我只需启用WiFi并执行第3步。
  7. 打印作业完成后,我只需禁用WiFi。这样,我们将重新连接到移动数据连接。(这是Android的默认设置)。

以下类将负责所有打印作业。

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) {

    }

}

通过以下链接的帮助,我创建了这个页面。 如果您想要打印文件,只需调用print(file)
如果您想要下载文件并打印,请调用downloadAndPrint(fileUrl, fileName)

你好,感谢您提供的解决方案。我发现市场上有很多打印机可用。请问,同样的解决方案是否适用于所有通用打印机?期待您的回复。 - Sharath
@SureshCS50,这个解决方案对我不起作用。我已经从你发布的链接中下载了你的Github项目,但它没有起作用。 - Vishali

7

我只能集成Bixolon SPP-R200的打印功能。他们有一个不错的SDK可用,而且很容易找到。我正在寻找8.5 x 11蓝牙功能,但是目前好像没有类似的sdk。


谢谢你的回答。稍后我会接受,如果没有其他人回答的话。在那之前加一。 - Gábor Lipták
你好TML,我在哪里可以获取Bixolon SPP-R200打印机的SDK。请帮忙。 - Jayabal
@baya 直接向Bixolon支持团队发送请求。Bixolon的支持电子邮件是:techsupp@bixolon.de。虽然这个电子邮件是德国的,但据我所知,这些人也会用英语回答。 - AgentKnopf

3

Star Micronics提供了适用于Android打印的SDK,支持蓝牙(以及wifi/以太网和USB)连接。您可以在此处下载:http://www.starmicronics.com/support/SDKDocumentation.aspx

正如上面所提到的,现在您不能原生地进行打印,因此您的选择是使用特定的打印机API或第三方打印应用程序。

根据我的经验,最好使用API而不是外部应用程序。最大的原因是您可以完全控制打印机的行为。如果API设计得合理,实施起来也很容易。使用第三方应用程序会受到限制,因为您无法按照自己的意愿自定义打印输出。

我向您提供的Star SDK配备了一个非常好的示例应用程序,可以让您测试和自定义许多打印机功能并查看其效果。每个功能在源代码中都有记录。命令及其参数也作为快速屏幕参考在应用程序本身中提供,非常方便。除此之外,它的文档编写得很好。

如果您选择这种方式,您可以将纯文本与命令一起发送到打印机。API会处理将数据转换为打印机可以理解的格式。


@LtH,请将相同的代码发送给我,以便与我的应用程序集成,在我的情况下它崩溃了。 - Ravi
@LtH 这适用于所有打印机吗? https://dev59.com/43_aa4cB1Zd3GeqP4ISg - Noufal

2

还有一个名为APF的Android打印SDK,它基于CUPS,支持多达数千种打印机。网站:isb-vietnam.com


2
Zebra Technologies 还提供了一个 Android SDK。我已经尝试过他们的 SDK 和 Bixolon 的(通过写信给 techsupp@bixolon.de 获得)。两者都可以正常工作,但如果你喜欢使用页面描述语言来定义文档,那么最好还是使用 Zebra 打印机。

SDK链接已经失效了,有人有解决方法吗?从Zebra网站上并不清楚这个是否还可用。这是它吗?https://www.zebra.com/us/en/products/software/barcode-printers/link-os/link-os-sdk.html - Jon B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接