【问题标题】:Bluetooth and WIFI Printing for Android适用于 Android 的蓝牙和 WIFI 打印
【发布时间】:2011-06-07 01:43:43
【问题描述】:

我们需要一台便携式打印机(手持,这很重要),可以通过蓝牙或 wifi 连接到安卓手机。

我目前知道的:

  • 这次没有适用于 Android 的标准打印 SDK
  • 有一个非官方的SDK,叫做iPrint SDK。你们有没有人通过wifi或蓝牙尝试过?有用吗?
  • Printershare 也声称是 programmaticly available。我可以为每部电话支付 5 美元的一次性费用。它有很多支持的格式。您是否尝试过使用任何手持设备?我向他们询问了支持的蓝牙打印机列表(因为它有一个菜单项“搜索 BT 打印机”),但他们没有回答。

以上我需要知道的:

  • 如何从 Android 应用打印?
  • 您使用哪种打印机?
  • 是否计划在标准 android SDK 中包含打印功能?路线图是什么?它现在是 Beta 版还是其他版本?
  • 如果我们以某种方式(我不这么认为)构建自己的蓝牙打印解决方案,您能否推荐标准和协议来检查和学习?

【问题讨论】:

标签: android printing bluetooth wifi printers


【解决方案1】:

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

这是原型的流程。

  1. 检查连接。
  2. 如果在 WiFi 中连接.. 正在存储该 WiFi 配置。
  3. 现在检查我是否已有打印机信息(WiFi 打印机的 WiFi 配置)是否可用。如果可用,我将扫描并获取 WiFi 扫描结果列表并连接到其他列表。它会显示 WiFi 列表并单击它,用户将连接到打印机并存储该 WiFi 配置以供将来打印作业。
  4. 打印作业完成后,我将连接到以前的 WiFi 或移动数据连接。
  5. 现在回到第二步。
  6. 如果用户在移动数据中连接,我只是启用 WiFi 并执行第 3 步。
  7. 打印作业完成后,我只是禁用了 WiFi。这样,我们将连接回移动数据连接。 (即安卓默认)。

下面的类将负责该原型中的所有打印作业。

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)

【讨论】:

  • 您好,感谢您提供的解决方案。我发现市场上有很多打印机。您能否告诉我,相同的解决方案是否适用于所有通用打印机?等待回复。
  • @SureshCS50 这个解决方案对我不起作用。我已经从您发布但不起作用的链接下载了您的 github 项目
【解决方案2】:

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

Android 应用现在可以通过 Wi-Fi 或云托管服务(例如 Google 云打印)打印任何类型的内容。在支持打印的应用中,用户可以发现可用的打印机、更改纸张尺寸、选择要打印的特定页面,以及打印几乎任何类型的文档、图像或文件。

如何启动打印过程的简单示例:

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

CustomPrintDocumentAdapter 扩展 PrintDocumentAdapter 的位置。

更多信息请访问Android Developers

【讨论】:

【解决方案3】:

Zebra Technologies 还提供SDK for Android。我已经尝试过他们的 SDK 和 Bixolon 的(通过写信给 techsupp@bixolon.de 得到)。两者都可以正常工作,但如果您更喜欢使用 page description language 来定义您的文档,您最好使用 Zebra 打印机。

【讨论】:

【解决方案4】:

Star Micronics 有一个 SDK,用于通过蓝牙(以及 wifi/以太网和 USB)进行 Android 打印。你可以在这里下载:http://www.starmicronics.com/support/SDKDocumentation.aspx

如上所述,您目前无法进行本地打印,因此您可以选择特定的打印机 API 或 3rd 方打印应用程序。

根据我的经验,最好使用 API 而不是外部应用程序。最大的原因是您可以完全控制打印机的行为。如果 API 是智能构建的,则很容易实现。使用 3rd 方应用程序会受到限制,因为您无法按照自己的方式自定义打印输出。

我链接到的 Star SDK 有一个非常棒的示例应用程序,可让您测试和自定义许多打印机功能以查看它们的实际运行情况。每个函数都记录在源代码中。命令及其参数也可在应用程序本身中作为快速屏幕参考,这很方便。最重要的是,它有据可查。

如果您选择这种方式,您可以将纯文本连同命令一起发送到打印机。 API 负责将数据转换为打印机可以理解的内容。

【讨论】:

【解决方案5】:

还有另一个用于 Android 的打印 SDK,称为 APF。它基于 CUPS,因此支持多达数千台打印机。网址:isb-vietnam.com

【讨论】:

    【解决方案6】:

    目前无法在 Android 上通过蓝牙进行打印(据我所知),因为 Android 不支持蓝牙“配置文件”,例如 BPP(基本打印配置文件)、HCRP(硬拷贝替换配置文件)、BIP(基本成像配置文件)等是蓝牙打印使用的常用配置文件。 参考。 this 了解打印 BT 配置文件。

    目前,Android 支持 OPP(Object Push Profile),用于通过蓝牙发送文件。

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

    对于 Wifi 打印,市场上有许多应用程序可让您从 Android 手机打印各种文档和图像。请参阅PrinterShare 了解此类应用程序。对于 Wifi 打印,您可以使用任何可以通过以太网 (LAN) 连接的打印机。

    还可以查看启用了“Google 云打印”的打印机,该打印机使用云打印到连接到世界任何地方且支持此协议的打印机。这在市场上是相当新的,但在未来几年肯定会受到关注。查看Cloud print app here。和faq here

    希望这有助于从您的清单中解决一些问题。

    【讨论】:

    • 查看stackoverflow.com/questions/1421326/bluetooth-on-android/… 了解有关蓝牙路线图的更多信息...
    • 感谢您的解释性回答。我很感激。
    • 这不是真的,通过蓝牙打印是不可能的,至少因为 PrinterShare 应用程序可以做到。
    • 您可以通过蓝牙轻松打印。大多数打印机都附带一个示例和/或 SDK,可帮助您将内容(文本和图像)打印到蓝牙。但是,如果你的目标是 SDK 28,谷歌对蓝牙通信施加了一些限制(我会说 Android 9 在蓝牙管理中有一个错误,他们会解决它)
    【解决方案7】:

    我能够集成的唯一印刷是 Bixolon SPP-R200。他们有一个不错的 SDK 可用并且很容易找到。我正在寻找 8 1/2 x 11 的蓝牙功能,但现在类似的 sdk 似乎是一个很高的要求

    【讨论】:

    • 感谢您的回答。一段时间后我会接受,如果没有其他人回答。在那之前 +1。
    • 您好 TML,我在哪里可以获取 Bixolon SPP-R200 打印机的 SDK。请帮忙。
    • @baya 直接写信给 bixolon 支持并请求它。 Bixolon 的支持电子邮件是:techsupp@bixolon.de。虽然这封邮件是德文的,但据我所知,这些人也是用英文回复的。
    猜你喜欢
    • 1970-01-01
    • 2012-11-30
    • 2012-04-07
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多