1# 文件打印(C/C++) 2 3<!--Kit: Basic Services Kit--> 4<!--Subsystem: Print--> 5<!--Owner: @guoshengbang--> 6<!--Designer: @gcw_4D6e0BBd--> 7<!--Tester: @guoshengbang--> 8<!--Adviser: @RayShih--> 9 10OS提供了两种打印方式: 11 12[方式一](#3-方式一通过接口拉起系统打印预览界面下发任务):应用通过接口拉起系统打印预览界面,传输渲染好的PDF文件进行打印任务下发。该方式适合有打印需求的应用使用系统能力快捷进行文件打印。 13 14[方式二](#4-方式二通过打印接口自主进行打印设备的发现连接和打印任务的下发):应用通过打印接口自主发现、连接打印设备并下发任务。该方式适合具有自己的打印预览界面的应用,可以通过接口打开打印设备发现、获取打印设备能力,构建打印预览界面需要的信息。 15 16> **说明:** 17> 18> 使用打印服务,需[声明权限](../../security/AccessToken/declare-permissions.md):ohos.permission.PRINT。 19> 20> 当不再使用打印服务时,调用OH_Print_Release()释放打印客户端资源并取消事件订阅。 21 22 23 24## 开发步骤 25 26### 1. 引用头文件 27 28```c++ 29#include <cstdint> 30#include <cstdio> 31#include <cwchar> 32#include <vector> 33#include <string> 34#include "hilog/log.h" 35#include "napi/native_api.h" 36#include "BasicServicesKit/ohprint.h" 37``` 38 39### 2. 在CMake脚本中添加动态链接库 40 41```txt 42target_link_libraries(entry PUBLIC 43 libace_napi.z.so 44 libhilog_ndk.z.so 45 libohprint.so 46) 47``` 48 49### 3. 方式一:通过接口拉起系统打印预览界面下发任务 50 51```ts 52import { Context } from '@kit.AbilityKit'; 53 54@Entry 55@Component 56struct Index { 57 build() { 58 Button("call native") 59 .onClick(() => { 60 let ctx = this.getUIContext().getHostContext();; // 获取 Ability 的 Context 61 if (ctx === undefined) { 62 console.error('get fileUri or context failed'); 63 return; 64 } 65 getContext(ctx); // 传给 C++ 侧 66 }); 67 } 68} 69``` 70 71```c++ 72// 使用系统打印下发打印任务 73static void* context; 74static char* currentJobId; 75 76// 初始化打印服务 77Print_ErrorCode ret = OH_Print_Init(); 78 79static napi_value getContext(napi_env env, napi_callback_info info) 80{ 81 size_t argc = 1; 82 napi_value argv[1] = {nullptr}; 83 // 假设 napi_get_cb_info 正常返回 84 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); 85 // 保存 context 于后续使用 86 napi_status ret = napi_unwrap(env, argv[0], &context); 87 return nullptr; 88} 89 90// 系统打印预览界面回调,首次拉起或用户修改打印参数时回调 91static void StartLayoutWriteCb(const char *jobId, 92 uint32_t fd, 93 const Print_PrintAttributes *oldAttrs, 94 const Print_PrintAttributes *newAttrs, 95 Print_WriteResultCallback writeCallback) 96{ 97 // 缓存任务Id,任务Id唯一 98 currentJobId = jobId; 99 // WriteFile 由开发者实现,获取当前用户修改前后的打印参数,渲染对应的打印文件写入fd。如黑白彩色,指定页码等。 100 uint32_t retCode = WriteFile(fd, oldAttrs, newAttrs); 101 // 通知打印系统文件写入完成 102 writeCallback(jobId, retCode); 103} 104 105// 打印文件写入完成后,系统打印预览界面会进行预览,此时用户可以点击“开始打印”下发任务。 106// 任务ID对应的打印状态变化的回调函数。 107static void JobStateChangedCb(const char *jobId, uint32_t state) 108{ 109 // 开发者根据任务id管理任务状态的逻辑 110} 111 112// 调用打印接口以拉起系统打印预览界面。 113char printJobName[] = "fileName"; 114Print_PrintDocCallback printDocCallback = { StartLayoutWriteCb, JobStateChangedCb }; 115Print_ErrorCode ret = OH_Print_StartPrintByNative(printJobName, printDocCallback, context); 116 117// 不再使用打印服务时释放资源 118OH_Print_Release() 119``` 120 121### 4. 方式二:通过打印接口自主进行打印设备的发现、连接和打印任务的下发 122 123```c++ 124// 初始化打印服务 125Print_ErrorCode ret = OH_Print_Init(); 126 127// 注册设备发现事件的回调,开始打印设备发现 128static void PrinterDiscoveryCallback(Print_DiscoveryEvent event, const Print_PrinterInfo *printerInfo) 129{ 130 // 发现一台打印设备,以设备Id作为唯一标识符 131 if (printerInfo == nullptr) { 132 OH_LOG_Print(LOG_APP, LOG_INFO, 0, "print c/c++", "printerInfo is nullptr"); 133 return; 134 } 135 // 开发者需根据具体业务场景实现以下回调逻辑 136 switch (event) { 137 // 发现打印设备事件 138 case PRINTER_DISCOVERED: 139 OnPrinterDiscovered(printerInfo); 140 break; 141 // 丢失打印设备事件 142 case PRINTER_LOST: 143 OnPrinterLost(printerInfo); 144 break; 145 // 打印机连接开始事件,由OH_Print_ConnectPrinter触发 146 case PRINTER_CONNECTING: 147 OnPrinterConnecting(printerInfo); 148 break; 149 // 打印机连接完成事件,由OH_Print_ConnectPrinter触发 150 case PRINTER_CONNECTED: 151 OnPrinterConnected(printerInfo); 152 break; 153 default: 154 break; 155 } 156} 157Print_PrinterDiscoveryCallback callback = PrinterDiscoveryCallback; 158Print_ErrorCode ret = OH_Print_StartPrinterDiscovery(callback); 159 160// 连接打印机,通过PrinterDiscoveryCallback获取到打印机属性,使用打印机ID进行连接 161// 连接成功后会收到PRINTER_CONNECTED事件。 162Print_ErrorCode ret = OH_Print_ConnectPrinter(printerInfo->printerId); 163 164// 当不需要使用发现功能时,停止设备发现 165Print_ErrorCode ret = OH_Print_StopPrinterDiscovery(); 166 167// 获取已添加的打印设备名称列表 168Print_StringList addedPrinterList = {0}; 169Print_ErrorCode ret = OH_Print_QueryPrinterList(&addedPrinterList); 170for (uint32_t index = 0; index < addedPrinterList.count; index++) { 171 Print_PrinterInfo *printerInfo = nullptr; 172 // 使用已添加的打印设备名称来获取打印设备属性。 173 ret = OH_Print_QueryPrinterInfo(addedPrinterList[index], &printerInfo); 174 // 业务代码 175 // 打印设备属性使用完成后需要释放资源 176 OH_Print_ReleasePrinterInfo(printerInfo); 177} 178// 在使用完打印设备名称列表后需要释放该列表资源。 179OH_Print_ReleasePrinterList(&addedPrinterList); 180 181// 下发打印任务 182// 本例子使用默认选项 printerInfo->defaultValue 作为打印任务参数来下发任务。 183std::vector<uint32_t> fdList = { 44, 45 }; 184Print_PrintJob* printJob = new Print_PrintJob{ jobName, 185 fdList.data(), 186 static_cast<uint32_t>(fdList.size()), 187 printerInfo->printerId, 188 1, // 打印份数 189 printerInfo->defaultValue.defaultPaperSource, 190 printerInfo->defaultValue.defaultMediaType, 191 printerInfo->defaultValue.defaultPageSizeId, 192 printerInfo->defaultValue.defaultColorMode, 193 printerInfo->defaultValue.defaultDuplexMode, 194 printerInfo->defaultValue.defaultResolution, 195 printerInfo->defaultValue.defaultMargin, 196 true, 197 printerInfo->defaultValue.defaultOrientation, 198 printerInfo->defaultValue.defaultPrintQuality, 199 DOCUMENT_FORMAT_PDF, 200 printerInfo->defaultValue.otherDefaultValues, }; 201Print_ErrorCode ret = OH_Print_StartPrintJob(printJob); 202delete printJob; 203 204// 不再使用打印服务时释放资源 205OH_Print_Release() 206```