
在android开发中,集成ml kit文本识别功能时,开发者常遇到“waiting for the text optional module to be downloaded”错误。这通常是由于使用了不恰当的ml kit依赖库版本或类型所致。本文将深入探讨此问题,并提供一个简洁有效的解决方案,确保文本识别模块能够正确下载并初始化,从而顺利实现图像到文本的转换功能。
ML Kit为Android应用提供了强大的机器学习能力,其中文本识别功能允许开发者将图像中的文本提取出来。在使用ML Kit进行文本识别时,特别是对于某些语言或高级功能,ML Kit可能需要下载额外的模型模块。当遇到“Waiting for the text optional module to be downloaded. Please wait.”这样的错误提示时,通常意味着应用未能成功地获取或初始化所需的文本识别模型。
这个问题的核心往往不在于网络连接或设备存储空间,而更多地与项目配置中引入的ML Kit依赖库有关。Google提供了多种方式来集成ML Kit,包括通过Google Play Services(适用于托管模型)和直接通过独立的ML Kit库(适用于设备端模型)。不正确的依赖选择可能导致模块无法按预期下载或加载。
解决“Waiting for the text optional module to be downloaded”错误的关键在于确保项目引入了正确的、包含设备端文本识别模型的ML Kit库。
许多开发者可能会错误地引入如下依赖:
implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.2' implementation 'com.google.android.gms:play-services-mlkit-text-recognition-common:18.0.0'
这些play-services-mlkit-*依赖是基于Google Play Services的ML Kit API,它们通常依赖于Google Play Services来管理模型的下载和更新。然而,对于某些设备端(on-device)的文本识别功能,更推荐直接使用ML Kit提供的独立库,它包含了所需的模型,减少了对Play Services特定版本或模块下载的依赖。
正确的解决方案是替换或补充以下依赖:
将上述play-services-mlkit-*依赖替换为(或确保项目中包含)com.google.mlkit:text-recognition。这个库直接包含了设备端的文本识别模型,通常能够避免模块下载的问题。
// 移除或注释掉: // implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.2' // implementation 'com.google.android.gms:play-services-mlkit-text-recognition-common:18.0.0' // 添加或更新为: implementation 'com.google.mlkit:text-recognition:16.0.0-beta6' // 使用最新的稳定版本,此处为示例版本
请注意,16.0.0-beta6是一个示例版本号,建议查阅ML Kit官方文档以获取最新的稳定版本。
步骤总结:
一旦依赖配置正确,您的MainActivity中的ML Kit文本识别逻辑应能正常工作。以下是关键部分的示例代码,展示了如何初始化和使用TextRecognizer:
package com.gorkemtand.textrecognition;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.PopupMenu;
import android.widget.Toast;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.imageview.ShapeableImageView;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.text.Text;
import com.google.mlkit.vision.text.TextRecognition;
import com.google.mlkit.vision.text.latin.TextRecognizerOptions; // 确保使用正确的TextRecognizerOptions
import java.io.IOException;
import java.util.Objects;
import android.Manifest; // 确保Manifest导入正确
public class MainActivity extends AppCompatActivity {
private MaterialButton inputImageBtn;
private MaterialButton recognizeTextBtn;
private ShapeableImageView imageIv;
private EditText recognizedTextEt;
private static final String TAG = "MAIN_TAG";
private Uri imageUri = null;
private static final int CAMERA_REQUEST_CODE = 100;
private static final int STORAGE_REQUEST_CODE = 101;
private String[] cameraPermissions;
private String[] storagePermissions;
private ProgressDialog progressDialog;
private TextRecognizer textRecognizer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化UI组件
inputImageBtn = findViewById(R.id.inputImageBtn);
recognizeTextBtn = findViewById(R.id.recognizeBtn);
imageIv = findViewById(R.id.imageIv);
recognizedTextEt = findViewById(R.id.recognizedTextEd);
// 初始化权限数组
cameraPermissions = new String[] {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
storagePermissions = new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE};
// 初始化进度对话框
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("请稍候");
progressDialog.setCanceledOnTouchOutside(false);
// 初始化TextRecognizer
// 使用TextRecognizerOptions.DEFAULT_OPTIONS来获取默认的设备端文本识别器
textRecognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS);
// 设置按钮点击监听器
inputImageBtn.setOnClickListener(v -> showInputImageDialog());
recognizeTextBtn.setOnClickListener(v -> {
if(imageUri == null){
Toast.makeText(MainActivity.this,"请先选择图片...",Toast.LENGTH_SHORT).show();
} else {
recognizeTextFromImage();
}
});
}
private void recognizeTextFromImage() {
Log.d(TAG, "recognizeTextFromImage: 开始识别文本");
progressDialog.setMessage("准备图片...");
progressDialog.show();
try {
// 从Uri创建InputImage
InputImage inputImage = InputImage.fromFilePath(this, imageUri);
progressDialog.setMessage("识别文本中...");
// 处理图片进行文本识别
textRecognizer.process(inputImage)
.addOnSuccessListener(text -> {
// 识别成功
progressDialog.dismiss();
String recognizedText = text.getText();
Log.d(TAG, "onSuccess: 识别到的文本: "+recognizedText);
recognizedTextEt.setText(recognizedText);
})
.addOnFailureListener(e -> {
// 识别失败
progressDialog.dismiss();
Log.e(TAG, "onFailure: 文本识别失败", e);
Toast.makeText(MainActivity.this,"文本识别失败: "+e.getMessage(),Toast.LENGTH_SHORT).show();
});
} catch (IOException e) {
// 处理图片准备失败
progressDialog.dismiss();
Log.e(TAG, "recognizeTextFromImage: 准备图片失败", e);
Toast.makeText(MainActivity.this,"准备图片失败: "+e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
// 省略 showInputImageDialog, pickImageGallery, pickImageCamera,
// ActivityResultLauncher, 权限检查和请求等相关方法,
// 这些方法在原代码中已经实现,且与ML Kit核心问题无关,但对于完整的应用是必需的。
// 确保这些方法中的权限处理和图片选择逻辑是健全的。
private void showInputImageDialog() {
PopupMenu popupMenu = new PopupMenu(this, inputImageBtn);
popupMenu.getMenu().add(Menu.NONE,1,1,"相机");
popupMenu.getMenu().add(Menu.NONE,2,2,"图库");
popupMenu.show();
popupMenu.setOnMenuItemClickListener(item -> {
int id = item.getItemId();
if(id == 1){
Log.d(TAG, "onMenuItemClick: 点击相机...");
if(checkCameraPermissions()){
pickImageCamera();
} else {
requestCameraPermissions();
}
} else if(id == 2){
Log.d(TAG, "onMenuItemClick: 点击图库...");
if(checkStoragePermision()){
pickImageGallery();
} else {
requestStoragePermission();
}
}
return false;
});
}
private void pickImageGallery(){
Log.d(TAG, "pickImageGallery: ");
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
galleryActivityResultLauncher.launch(intent);
}
private ActivityResultLauncher<Intent> galleryActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if(result.getResultCode() == RESULT_OK){
Intent data = result.getData();
if (data != null) {
imageUri = data.getData();
Log.d(TAG, "onActivityResult: imageUri "+imageUri);
imageIv.setImageURI(imageUri);
}
} else {
Log.d(TAG, "onActivityResult: 取消");
Toast.makeText(MainActivity.this,"已取消...",Toast.LENGTH_SHORT).show();
}
}
);
private void pickImageCamera(){
Log.d(TAG, "pickImageCamera: ");
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "示例标题");
values.put(MediaStore.Images.Media.DESCRIPTION, "示例描述");
imageUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
cameraActivityResultLauncher.launch(intent);
}
private ActivityResultLauncher<Intent> cameraActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if(result.getResultCode() == RESULT_OK){
Log.d(TAG, "onActivityResult: imageUri "+imageUri);
imageIv.setImageURI(imageUri);
} else {
Log.d(TAG, "onActivityResult: 取消");
Toast.makeText(MainActivity.this,"已取消", Toast.LENGTH_SHORT).show();
}
}
);
private boolean checkStoragePermision(){
return ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == (PackageManager.PERMISSION_GRANTED);
}
private void requestStoragePermission(){
ActivityCompat.requestPermissions(this,storagePermissions,STORAGE_REQUEST_CODE);
}
private boolean checkCameraPermissions(){
boolean cameraResult = ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA) == (PackageManager.PERMISSION_GRANTED);
boolean storageResult = ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_EXTERNAL_STORAGE) == (PackageManager.PERMISSION_GRANTED);
return cameraResult && storageResult;
}
private void requestCameraPermissions(){
ActivityCompat.requestPermissions(this,cameraPermissions, CAMERA_REQUEST_CODE);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case CAMERA_REQUEST_CODE:{
if (grantResults.length > 0){
boolean cameraAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean storageAccepted = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if(cameraAccepted && storageAccepted){
pickImageCamera();
} else {
Toast.makeText(this, "需要相机和存储权限", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this,"已取消",Toast.LENGTH_SHORT).show();
}
}
break;
case STORAGE_REQUEST_CODE:{
if(grantResults.length > 0){
boolean storageAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
if (storageAccepted) {
pickImageGallery();
} else {
Toast.makeText(this, "需要存储权限", Toast.LENGTH_SHORT).show();
}
}
}
break;
}
}
}AndroidManifest.xml 权限配置: 确保您的AndroidManifest.xml文件中声明了必要的权限:
<uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 如果目标API级别是33或更高,可以考虑使用READ_MEDIA_IMAGES替代WRITE_EXTERNAL_STORAGE --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
对于Android 13 (API 33) 及更高版本,推荐使用READ_MEDIA_IMAGES权限来访问媒体文件,而不是WRITE_EXTERNAL_STORAGE。
“Waiting for the text optional module to be downloaded”错误是ML Kit文本识别集成中常见的陷阱,但通过选择正确的com.google.mlkit:text-recognition依赖库,可以有效地解决此问题。理解不同ML Kit依赖的用途,并遵循官方推荐的集成方式,是确保应用稳定性和性能的关键。通过本文提供的解决方案和注意事项,开发者可以更顺利地在Android应用中实现强大的文本识别功能。
以上就是解决Android ML Kit文本识别模块下载失败的教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号