拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Android二维码开发实战:基于ZXing的高性能扫描与生成工具库

简介这是一套面向Android开发者与移动应用工程师的二维码全栈开发工具包基于ZXing开源库深度定制解决移动场景下高鲁棒性扫描、个性化二维码生成及批量业务处理等核心需求适用于移动支付、电子票务、商品溯源等商用场景。资源包共71个文件涵盖20个Java核心逻辑类含扫描引擎与生成器、24个XML布局与配置文件、8个PNG图标资源、4个Gradle构建脚本以及proguard混淆规则、Git配置、README说明文档等结构清晰便于二次开发与模块复用压缩包仅1.05MB轻量高效。配套提供附赠资源.docx技术文档、说明文件.txt使用指南及ZXingCameras-master源码参考覆盖API调用示例、logo嵌入算法实现、批量识别线程调度策略等关键细节显著降低集成门槛与调试成本。1. 项目概述一个Android端的全能二维码工具箱最近在做一个移动端的项目里面涉及到大量的二维码交互场景从用户扫码支付到后台的商品信息追溯都需要一个稳定可靠的二维码处理模块。市面上虽然有很多现成的SDK但要么功能单一要么封装过度想自定义个logo或者批量生成一批带不同参数的码都得费不少功夫。于是我决定基于老牌且强大的ZXing开源库自己动手封装一个功能全面、易于集成的Android二维码工具库。这个工具库的核心目标很明确它不仅要能扫还要能生更要好用。具体来说它实现了高精度的二维码扫描与识别支持生成可嵌入自定义Logo的二维码并且提供了批量生成与解析的便捷功能。更重要的是它深度适配了Android平台的各种特性比如相机API的兼容性、权限动态申请、以及针对不同场景如移动支付、电子票务的强光/弱光环境的识别优化。最终我将这些功能模块化打包成了一个可以直接引入Android Studio项目的.zip压缩包里面包含了完整的库模块、示例Demo和详细的集成文档。如果你正在开发一个涉及二维码功能的App无论是需要让用户扫码跳转链接、完成支付还是需要后台生成带品牌Logo的优惠券二维码这个工具都能帮你省去大量从零造轮子的时间。接下来我就把这个项目的核心设计思路、关键实现细节以及我踩过的一些坑毫无保留地分享出来。2. 核心功能设计与技术选型考量2.1 为什么选择ZXing作为核心引擎在Android平台处理二维码可选方案不少比如ZBar、ML Kit等。我最终选择ZXingZebra Crossing是基于以下几个扎实的考量首先生态成熟与社区活跃度。ZXing是一个历史悠久的、支持多种条码格式如QR Code, Data Matrix, PDF 417等的开源库由Google团队维护。这意味着它经过了无数项目的检验代码稳定遇到问题也容易在社区找到解决方案。相比之下一些较新的库可能在某些边缘机型或复杂场景下表现不稳定。其次可控性与可定制性。ZXing提供了从底层解码到上层UI的完整组件但它的架构是松耦合的。我可以只引入其核心的core和android-core模块然后完全自己掌控相机预览、界面交互和结果处理的流程。这对于需要深度定制扫描UI比如实现支付宝那种全屏扫描动画或者优化特定场景识别率的项目来说是至关重要的。再者生成功能的完备性。ZXing的编码器QRCodeWriter功能强大且灵活支持设置纠错等级、边距、尺寸等所有二维码标准参数。这为我们实现自定义Logo嵌入、批量生成等高级功能提供了坚实的基础。有些轻量级库可能只侧重扫描生成功能就很弱。最后是协议友好。ZXing采用Apache 2.0协议商业使用友好没有额外的法律风险。注意ZXing库本身比较庞大直接引入整个android模块可能会增加APK体积。我的做法是进行“瘦身”只保留必要的类并利用ProGuard或R8进行代码混淆和优化最终核心库体积可以控制在200KB以内。2.2 整体架构设计模块化与分层为了让这个工具库清晰、易用且易于维护我采用了典型的分层架构设计核心层Core Layer这一层是基础直接依赖ZXing的core库。它封装了最原始的二维码编解码能力包含两个核心类QrCodeGenerator负责二维码的生成逻辑接收文本内容、尺寸、纠错等级等参数输出一个Bitmap对象。自定义Logo的嵌入算法也在这里实现。QrCodeDecoder负责二维码的解析逻辑接收一个Bitmap或YUV图像数据输出解码后的文本字符串和格式信息。这里集成了图像预处理如二值化、旋转校正的逻辑以提升识别率。Android平台层Platform Layer这一层处理所有与Android系统交互的部分是工具库能“跑”在手机上的关键。CameraController统一管理相机设备的打开、关闭、参数配置对焦模式、分辨率、闪光灯以及预览帧数据的回调。它需要处理Android不同版本Camera1 API vs Camera2 API的兼容性问题这是扫描稳定性的核心。PermissionHelper封装了相机、存储等权限的动态申请逻辑遵循Android最佳实践提供简洁的异步回调接口。ImageProcessor负责将从相机获取的原始YUV_420_888或NV21数据转换为ZXing解码器所需的PlanarYUVLuminanceSource。这里可以加入图像增强算法比如在暗光下提亮、在强光下降低对比度。功能层Feature Layer这一层将核心能力包装成面向业务的高级功能。ScanActivity/ScanFragment可即插即用的扫描界面组件内置了扫描框、手电筒开关、相册选取等UI。开发者可以直接继承或嵌入使用。BatchQrCodeProcessor批量处理功能的核心。它内部使用线程池管理并发任务无论是批量生成1000个不同的二维码图片还是从相册中选取9张图进行批量解析都能高效完成并提供进度回调。FormatSupportManager管理多种格式的解析。除了标准的QR Code还可以扩展支持解析ISBN图书码、Wi-Fi网络配置信息、联系人信息vCard等格式并返回结构化的数据对象而不仅仅是字符串。接口层API Layer这是库对外的门面提供简单明了的静态方法或建造者Builder模式接口让集成只需几行代码。这样的分层设计使得底层编解码逻辑、平台适配和上层业务功能解耦。未来如果需要替换ZXing的核心引擎或者适配新的相机API只需要修改对应的层不会波及整个项目。3. 核心实现细节与避坑指南3.1 高精度二维码识别的三大优化策略直接使用ZXing的默认解码器在理想光照和角度下没问题但在实际移动场景中用户可能手抖、光线可能过暗或过曝、二维码可能印在曲面瓶身上。要实现“高精度”必须加入优化策略。策略一智能图像预处理相机采集的原始图像并不直接适合解码。我的ImageProcessor会执行以下流水线操作灰度化将彩色图转为灰度图减少计算量。自适应二值化这是关键简单的全局阈值如127在光照不均时会失效。我采用了局部自适应阈值算法如OpenCV中的adaptiveThreshold它能为图像中每个像素点根据其周围区域独立计算阈值有效应对阴影和反光。透视校正如果二维码在图像中严重倾斜识别率会骤降。我通过ZXing检测到的ResultPoint二维码的三个定位角点来计算透视变换矩阵然后将图像“拉正”再进行解码。这个步骤对扫描贴在墙角或圆柱体上的二维码特别有用。// 伪代码示例在解码前进行透视校正 public Bitmap perspectiveCorrection(Bitmap srcBitmap, ResultPoint[] points) { // points[0], points[1], points[2] 是二维码的三个角点 // 计算目标矩形的四个顶点例如基于points计算出的最小外接矩形 Point[] srcPoints convertResultPointsToPoints(points); Point[] dstPoints calculateDestinationRect(srcPoints); // 使用Android的Matrix或OpenCV进行透视变换 Matrix matrix new Matrix(); matrix.setPolyToPoly(srcPoints, dstPoints); Bitmap correctedBitmap Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true); return correctedBitmap; }策略二多帧合成与智能重试单帧解码失败是常事。我的做法是在预览回调中不是每帧都尝试解码而是以一定频率如每秒5-10次抽取帧进行解码。如果连续多次失败我会自动触发以下重试机制调整对焦调用CameraController尝试一次对焦。调节曝光在暗光下适当增加曝光补偿值。切换识别区域除了屏幕中央的扫描框也会尝试对全图进行识别以防用户没有对准。策略三结果验证与去重快速移动手机时可能连续几帧都识别出同一个二维码导致回调被多次触发。我实现了一个简单的防抖机制记录最近一次成功解码的结果和时间戳如果在500毫秒内识别到相同内容则忽略后续结果。实操心得图像预处理很耗CPU。务必在后台线程中进行并控制频率。对于adaptiveThreshold这样的操作可以先将图像缩放至一个合理的宽度如800px再处理能大幅提升性能。同时要提供开关让开发者根据应用场景选择是否启用这些高级优化因为对于大部分“对准即扫”的场景默认解码可能已经足够。3.2 支持自定义Logo嵌入的二维码生成详解生成带Logo的二维码不是简单地把Logo图片贴在二维码中央那么简单。粗暴地覆盖会破坏二维码的编码数据导致无法识别。正确的做法需要兼顾Logo的展示和二维码的容错能力。核心原理利用纠错码Error Correction空间QR码有四个纠错等级L低约7%、M中约15%、Q四分约25%、H高约30%。这意味着即使部分编码区域被损坏或遮挡只要不超过相应比例仍然可以正确解码。我们嵌入Logo本质上就是在“故意损坏”中央区域的数据而纠错码会负责修复它。实现步骤生成原始二维码Bitmap使用ZXing的QRCodeWriter生成一个不含Logo的、纠错等级为H推荐的二维码位图。尺寸建议设置得大一些比如500x500像素为后续插入Logo预留质量空间。处理Logo图片尺寸计算Logo不宜过大否则会占用过多纠错空间。一个经验法则是Logo的宽度不超过二维码整体宽度的1/5。例如500px的二维码Logo宽度应在100px以内。形状与背景将Logo处理为正方形并为其添加一个白色或与二维码背景色一致的边框padding。这个边框非常重要它能在Logo和二维码的黑白模块之间形成一个“缓冲带”减少边缘干扰提高识别率。我通常设置边框为Logo宽度的10%-15%。圆角处理将Logo的四个角做成圆角这比直角更能减少对二维码矩阵的“攻击性”。合成图像将原始二维码Bitmap转换为可修改的MutableBitmap。计算二维码Bitmap的中心坐标。将处理好的带边框的Logo Bitmap绘制到原始二维码Bitmap的中心位置。可选后处理为了进一步确保识别率可以在合成后对Logo覆盖区域的边缘进行轻微的模糊或稀释处理让黑白过渡更自然。// 伪代码示例生成带Logo的二维码 public Bitmap createQrCodeWithLogo(String content, int size, Bitmap logo) { // 1. 生成原始高纠错等级二维码 MapEncodeHintType, Object hints new HashMap(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); hints.put(EncodeHintType.MARGIN, 1); BitMatrix bitMatrix new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, size, size, hints); Bitmap qrBitmap bitMatrixToBitmap(bitMatrix); // 将BitMatrix转为Bitmap // 2. 处理Logo int logoWidth qrBitmap.getWidth() / 5; // 宽度为二维码1/5 Bitmap scaledLogo scaleAndAddBorder(logo, logoWidth); // 缩放并加白边 // 3. 合成 Bitmap result qrBitmap.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas new Canvas(result); int left (qrBitmap.getWidth() - scaledLogo.getWidth()) / 2; int top (qrBitmap.getHeight() - scaledLogo.getHeight()) / 2; canvas.drawBitmap(scaledLogo, left, top, null); return result; }避坑指南务必提醒使用者即使采用了高纠错等级Logo也不宜过于复杂或色彩对比度低。简单的单色、高对比度的品牌图形是最佳选择。在生成后务必用多种扫描工具包括微信、支付宝进行测试确保兼容性。3.3 批量处理功能的高效实现“批量处理”功能在后台管理、物料制作等场景非常实用。它的核心挑战在于性能和内存管理处理成百上千张图片时不能阻塞主线程或导致OOM内存溢出。架构设计生产者-消费者模型我使用了一个固定的线程池ThreadPoolExecutor来执行任务。将每个二维码的生成或解析任务封装为一个Runnable或Callable对象提交到线程池的队列中。任务队列使用LinkedBlockingQueue来管理待处理的任务。线程池配置核心线程数根据设备CPU核心数动态设置通常为Runtime.getRuntime().availableProcessors()最大线程数适当放宽并设置合理的空闲线程存活时间。队列大小需要限制防止内存积压。进度反馈通过Handler或LiveData将每个任务的完成进度、成功/失败状态回调到主线程的UI上更新进度条。结果聚合所有任务完成后将结果生成的图片路径列表或解析出的文本列表进行汇总并通过回调一次性返回。内存优化关键点Bitmap复用与回收在批量生成时用于渲染二维码的画布Canvas和临时Bitmap可以复用。每处理完一张图片立即调用Bitmap.recycle()在确认不再需要后并置空引用帮助GC回收。磁盘缓存替代内存缓存对于批量生成的大量图片不应全部保存在内存的ListBitmap中。我的做法是每生成一张Bitmap立即将其压缩compress并写入到应用缓存目录下的一个临时文件然后在结果列表中保存文件路径。这样内存中始终只保留当前正在处理的少数几个Bitmap对象。任务取消与中断必须提供取消批量任务的功能。这需要在线程池的Runnable中定期检查中断状态并在Activity/Fragment销毁时主动关闭线程池避免内存泄漏。// 伪代码示例批量生成二维码任务 public class BatchGenerateTask { private ExecutorService mExecutor; private ListString mContentList; private String mOutputDir; public void start(OnBatchProgressListener listener) { mExecutor Executors.newFixedThreadPool(4); // 固定4个线程 int total mContentList.size(); CountDownLatch latch new CountDownLatch(total); AtomicInteger successCount new AtomicInteger(0); for (int i 0; i total; i) { final int index i; mExecutor.submit(() - { try { Bitmap qr generateSingleQrCode(mContentList.get(index)); File file saveBitmapToFile(qr, mOutputDir, qr_ index .png); qr.recycle(); successCount.incrementAndGet(); // 回调进度 runOnUiThread(() - listener.onProgress(index 1, total, file.getPath())); } catch (Exception e) { // 处理错误 } finally { latch.countDown(); } }); } // 等待所有任务完成 new Thread(() - { try { latch.await(); mExecutor.shutdown(); ListFile resultFiles collectResultFiles(mOutputDir); runOnUiThread(() - listener.onComplete(successCount.get(), resultFiles)); } catch (InterruptedException e) { // 处理中断 } }).start(); } }4. Android平台集成与性能调优实战4.1 相机兼容性处理Camera1 vs Camera2 APIAndroid相机开发的一大痛点就是API的碎片化。旧设备使用已废弃的CameraAPICamera1新设备推荐使用Camera2API而最新的CameraX虽然好用但依赖Jetpack库。为了最大兼容性我的CameraController实现了自动降级策略。检测与选择策略首先检查设备支持的Android版本和相机硬件特性。如果设备API Level 21Android 5.0且相机支持Camera2API的LEGACY或更高级别则优先使用Camera2。Camera2提供了更精细的控制如手动对焦、曝光并且在许多新设备上性能更好。如果不满足条件则自动回退到Camera1API。虽然功能受限但兼容性最广。统一接口封装无论底层使用哪个API我都向上层扫描界面提供统一的接口包括startPreview()stopPreview()setFlashlight(boolean)setFocusMode(...)以及一个用于接收预览帧数据的回调PreviewFrameCallback。这样业务层无需关心底层实现。Camera2 API使用的注意事项状态机管理Camera2的操作是异步的基于状态机。打开相机、创建会话等操作都需要在回调中处理。必须妥善管理CameraDevice.StateCallback和CameraCaptureSession.StateCallback的生命周期防止在Activity停止后仍调用相机导致崩溃。图像格式选择从ImageReader获取预览帧时选择ImageFormat.YUV_420_888格式这是最通用且高效的格式方便后续直接传递给ZXing的PlanarYUVLuminanceSource。预览尺寸选择不是选择最高分辨率而是选择与屏幕预览控件宽高比最接近、且分辨率适中的尺寸。过高的分辨率会导致预览帧数据量巨大处理延迟增高。我通常会先获取设备支持的所有预览尺寸然后按以下优先级筛选1. 比例匹配屏幕2. 分辨率在1080p以下3. 选择该条件下最大的尺寸。踩坑实录在某些国产定制ROM上Camera2API的行为可能与原生Android有差异。例如LEGACY级别的设备可能不支持某些高级功能或者ImageReader的输出格式不稳定。因此在CameraController中必须加入大量的异常捕获和降级逻辑。一个实用的技巧是在初始化时先用Camera2尝试打开相机并获取一帧数据如果超时或失败立即回退到Camera1并将此设备的“偏好API”记录在本地下次启动时直接使用。4.2 权限管理与动态申请的最佳实践相机和存储权限是必须的。Android 6.0 (API 23) 之后需要动态申请。我的PermissionHelper类封装了这套逻辑。设计思路单一职责这个类只负责权限的检查、申请和结果回调。链式调用提供流畅的API例如new PermissionHelper(this) .withPermission(Manifest.permission.CAMERA) .withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) // 如果需要保存图片 .setRationaleMessage(需要相机权限来扫描二维码) .setDeniedMessage(请在设置中手动开启权限) .setCallback(new PermissionCallback() { Override public void onGranted() { /* 权限全部 granted 打开相机 */ } Override public void onDenied(ListString deniedPermissions) { /* 处理被拒绝的权限 */ } }) .request();处理“不再询问”如果用户拒绝了权限并勾选了“不再询问”下次shouldShowRequestPermissionRationale()会返回false。此时我们需要引导用户跳转到应用设置页面去手动开启权限。PermissionHelper内部会判断这种情况并在setDeniedMessage中提示用户去设置。在扫描组件中的集成在ScanActivity的onCreate或onResume中检查相机权限。如果没有权限则显示一个覆盖层引导用户授权而不是直接黑屏。权限获取后再初始化相机。这样用户体验更连贯。4.3 内存与性能优化要点二维码扫描是一个实时性要求较高的功能必须保证流畅不卡顿。预览帧处理优化降低采样频率不需要处理每一帧预览数据。可以设置一个时间间隔如200毫秒或者只在相机对焦成功后的几帧内进行解码。裁剪识别区域通常用户会将二维码对准扫描框。因此解码时只截取扫描框对应区域的图像数据而不是处理全图能大幅减少数据量。可以通过YUV_420_888数据的Plane和RowStride来精确计算和裁剪。使用Native代码ZXing的核心解码库是C的在JNI层调用。这本身已经很快。但我们自己的图像预处理如透视校正如果非常复杂可以考虑用RenderScript或直接使用OpenCV的Native库来加速。Bitmap生命周期管理在onPause时立即释放相机和相关的Bitmap资源。在ImageView中显示二维码时根据View的实际大小来加载缩放后的图片避免加载一张2000x2000的大图到一个200x200的ImageView里。可以使用BitmapFactory.Options.inSampleSize进行采样。对于批量生成功能中产生的临时Bitmap如前所述要立即回收。避免内存泄漏相机、CameraCaptureSession等资源必须在Activity/Fragment的onDestroy中正确关闭和释放。将解码操作放在单独的HandlerThread中并在页面销毁时退出该线程的Looper。所有回调接口如扫描结果回调使用弱引用WeakReference来持有外部Activity的引用或者确保在页面销毁时取消注册。5. 多种格式解析与扩展应用场景5.1 超越文本结构化数据解析标准的二维码解码出来是一个字符串。但很多场景下这个字符串是遵循特定格式的比如WIFI:S:SSID;T:WPA/WEP;P:密码;;Wi-Fi网络配置。BEGIN:VCARD...END:VCARD联系人信息。tel:电话号码拨打电话。smsto:号码:内容发送短信。我的FormatSupportManager模块内置了这些常见格式的解析器。当解码器返回一个字符串后FormatSupportManager会尝试用一系列正则表达式或专门的解析器如用于vCard的库去匹配它。如果匹配成功则返回一个结构化的数据对象如WifiConfig、ContactInfo而不仅仅是原始字符串。这样上层应用可以直接获取到语义化的字段无需再自己拆分字符串大大提升了开发效率。5.2 典型应用场景实现方案移动支付生成根据支付协议如支付宝、微信支付的URL格式生成收款码。关键是要确保生成的二维码符合支付平台的官方规范尺寸、边距、纠错等级。扫描除了识别支付码还需要处理从相册选取付款码截图的情况。这里需要强化图像预处理特别是对截图可能存在的摩尔纹、压缩失真进行处理。电子票务生成票务二维码通常包含加密的票务ID、场次、座位等信息。生成后可以调用系统的“添加到钱包”如Google PayAPI提供深色背景、带Logo的二维码图片作为“通行证”的图标。扫描验票端需要高速、连续扫描。我的扫描组件提供了“连续扫描模式”在识别到一个二维码后仅暂停很短时间如1秒就自动恢复扫描适合闸机场景。同时验票逻辑如网络验证、本地解密可以与扫描结果回调解耦通过事件总线或接口传递给专门的业务模块处理。商品溯源生成批量生成是核心。每个二维码对应一个唯一的商品ID。可以将ID、生产批次、日期等信息编码并可能加入简单的防伪签名如HMAC。扫描消费者扫描后App解析出商品ID然后跳转到一个H5页面或调用后端API查询详细的溯源信息生产流程、质检报告、物流轨迹。这里二维码充当了一个入口的角色。工具库需要提供便捷的方式让开发者能将扫描到的文本与一个自定义的Action如打开特定URL绑定。6. 常见问题排查与调试技巧在实际集成和使用过程中你可能会遇到以下问题。这里我整理了一份速查表和一些调试心得。问题现象可能原因排查步骤与解决方案扫描时预览画面卡顿或延迟高1. 预览分辨率设置过高。2. 每帧都进行全图解码CPU过载。3. 图像预处理算法过于复杂。1. 在CameraController中打印并选择更低的预览尺寸如720p。2. 降低解码频率例如每200毫秒解码一次或只在onFocusSuccess回调后解码3帧。3. 简化预处理或将其移至Native层。某些手机扫描不出二维码1. 相机对焦模式不匹配。2. 预览帧数据格式转换错误。3. 特定ROM的相机兼容性问题。1. 尝试切换对焦模式为CONTINUOUS_PICTURE或AUTO。2. 检查YUV到LuminanceSource的转换代码确保rowStride和pixelStride计算正确。可以保存一帧原始数据到文件用电脑工具查看。3. 启用Camera1回退策略并收集日志。生成的带Logo二维码无法被某些扫码器识别1. Logo过大超出了纠错能力。2. Logo颜色与二维码模块对比度不够。3. 没有添加Logo边框。1. 缩小Logo尺寸至二维码宽度的1/5或更小。2. 确保Logo是深色黑/深蓝在浅色背景上或反之。避免使用中间色调。3. 务必为Logo添加白色边框。用微信、支付宝、专业扫码工具交叉测试。批量生成时App卡死或OOM1. 所有任务同步执行阻塞主线程。2. 生成的Bitmap未及时回收全部缓存在内存中。1. 确保使用线程池异步执行任务并通过Handler或LiveData更新UI进度。2. 采用“生成-保存-回收”流水线立即将Bitmap保存为文件并调用recycle()。使用Android Profiler监控内存使用情况。从相册选取的二维码图片无法识别1. 图片尺寸过大解码前未缩放。2. 图片存在旋转Exif信息。3. 图片格式为WebP或HEIC解码异常。1. 使用BitmapFactory.Options.inSampleSize进行大图采样。2. 读取图片的Exif旋转信息并使用Matrix进行旋转校正后再解码。3. 使用ContentResolver和BitmapFactory时优先尝试将其解码为JPEG或PNG格式的流。调试技巧开启详细日志在ZXing的DecodeHandler和我的ImageProcessor中打上详细的日志记录每一帧的处理时间、图像尺寸、解码状态。这能帮你快速定位性能瓶颈或识别失败的原因。保存失败帧在测试阶段可以修改代码将识别失败的预览帧图像保存到手机存储中。然后你可以用电脑上的二维码生成工具和这个失败图片进行对比分析是图像模糊、光线问题还是算法缺陷。使用模拟器与真机结合测试模拟器方便测试各种屏幕尺寸和API版本但相机行为是模拟的。真机测试必不可少尤其要覆盖低端机和各种国产ROM以发现兼容性问题。这个基于ZXing的二维码工具库从满足基本需求出发逐步深入到性能优化、兼容性处理和场景化扩展几乎涵盖了我能想到的所有二维码相关需求。封装成库之后在新项目里集成只需要添加依赖、配置权限、然后调用几个简单的API开发效率提升非常明显。如果你在集成或使用过程中有新的想法或遇到了奇怪的问题欢迎一起交流探讨。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门