您现在的位置是:网站首页> Android
AI辅助Android编程
- Android
- 2026-06-03
- 798人已阅读
AI辅助Android编程
***利用AI进行同代码的语言转换***

详细介绍Android JAVA中使用车牌识别库HyperLPR详细步骤及例子代码
AI编写Android代码提示词收集
你是一名优秀的Android开发工程师,给出国内网络环境可下载库的Android Studio项目配置
EMUI系统拦截通知栏第一次启动app拦截成功,后续再启动拦截app失败
####[豆包]
Q:你是一名优秀的Android开发工程师,给出国内网络环境可下载库的Android Studio项目配置
A:...
在国内网络环境下开发 Android 项目,最大的痛点是 Google 官方仓库访问慢、甚至无法访问。下面我为你提供一套完整的、适配国内网络环境的 Android Studio 项目配置方案,核心是替换为阿里云的镜像源。
一、项目级 build.gradle (Project) 配置
这是项目根目录下的 build.gradle 文件,主要配置仓库源和构建插件版本:
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id 'com.android.application' version '8.2.2' apply false id 'com.android.library' version '8.2.2' apply false // 如果使用Kotlin,添加这行 id 'org.jetbrains.kotlin.android' version '1.9.20' apply false } // 构建脚本配置 buildscript { repositories { // 1. 优先使用阿里云镜像(核心:替换Google/MavenCentral) maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/public' } // 备用:如果阿里云镜像有问题,可保留国内jcenter镜像 maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } } dependencies { classpath 'com.android.tools.build:gradle:8.2.2' // Kotlin插件(按需添加) classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20" // 其他插件(如Hilt、Room等,按需添加) } } // 所有模块共用的仓库配置 allprojects { repositories { // 2. 同样替换为阿里云镜像 maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } maven { url 'https://maven.aliyun.com/repository/central' } maven { url 'https://maven.aliyun.com/repository/public' } // 可选:添加国内常用的第三方仓库 maven { url 'https://jitpack.io' } // 用于GitHub开源库 maven { url 'https://dl.bintray.com/umsdk/release' } // 友盟等SDK } } // 清理构建缓存(可选) task clean(type: Delete) { delete rootProject.buildDir }
二、模块级 build.gradle (Module) 配置
这是 app 模块下的 build.gradle 文件,核心是确保依赖下载走国内源(上面已配置),同时给出通用基础配置:
plugins { id 'com.android.application' // 启用Kotlin(按需) id 'org.jetbrains.kotlin.android' } android { namespace "com.example.yourproject" compileSdk 34 defaultConfig { applicationId "com.example.yourproject" minSdk 21 targetSdk 34 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } // 配置Java/Kotlin编译版本 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = '1.8' } // 启用视图绑定(可选) buildFeatures { viewBinding true } } dependencies { // 基础依赖(国内源可快速下载) implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' // 测试依赖 testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' }
三、gradle-wrapper.properties 配置(关键)
这个文件在 gradle/wrapper/ 目录下,用于指定 Gradle 版本和下载源,替换为国内镜像:
distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists # 替换Gradle下载地址为阿里云镜像 distributionUrl=https\://mirrors.aliyun.com/maven/repository/gradle/gradle-8.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists
四、全局 gradle 配置(可选,推荐)
如果你想让所有 Android 项目都默认使用国内源,可以修改 Android Studio 的全局 gradle 配置:
1.打开 File > Settings > Build, Execution, Deployment > Build Tools > Gradle
2.找到 Gradle user home 对应的目录(通常是 C:\Users\你的用户名\.gradle)
3.在该目录下新建 init.gradle 文件,内容如下:
allprojects {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url 'https://maven.aliyun.com/repository/public' }
// 优先使用本地仓库(可选)
mavenLocal()
// 禁用原有的Google/MavenCentral(避免冲突)
google { enable() }
mavenCentral { enable() }
jcenter { enable() }
}
}
buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/repository/central' }
}
}
####【豆包】
A:...
Q:转成java代码
A:...
添加权限:
<uses-permission android:name="android.permission.WAKE_LOCK" />
代码:
import android.content.Context;
import android.os.Bundle;
import android.os.PowerManager;
import androidx.appcompat.app.AppCompatActivity;
public class WakeLockActivity extends AppCompatActivity {
private PowerManager.WakeLock wakeLock;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wake_lock);
// 获取PowerManager系统服务
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
// 创建WakeLock实例
wakeLock = powerManager.newWakeLock(
PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
"MyApp:KeepScreenOnTag" // 自定义标签,用于调试
);
// 持有WakeLock(保持屏幕常亮)
if (!wakeLock.isHeld()) {
wakeLock.acquire();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 必须释放WakeLock,否则会持续耗电
if (wakeLock != null && wakeLock.isHeld()) {
wakeLock.release();
}
}
}
五、额外注意事项
1.版本适配:上述配置中的插件 / 依赖版本是稳定版,你可以根据需要升级,但确保版本号与 Gradle 版本兼容(如 Gradle 8.x 对应 AGP 8.x)。
2.代理设置:如果你的网络需要代理,在 Android Studio 中配置:File > Settings > Appearance & Behavior > System Settings > HTTP Proxy,填写代理信息并勾选 Auto-detect proxy settings。
3.依赖下载失败:如果个别库下载失败,可优先检查:
仓库源是否配置正确;
依赖版本是否存在(可在阿里云镜像仓库查询:https://maven.aliyun.com/mvn/view);
清理 Gradle 缓存:File > Invalidate Caches / Restart。
####【豆包】
编写一个让Android不休眠的apk,并开机自运行,程序退出后自动重启
。。。
####【豆包】
Android开发中Gradle是干啥的
。。。
####【豆包】
Android Studio JAVA项目里加第三方库的方法有哪些给出具体例子
。。。
####【豆包】
通过远程仓库添加的库下载后位置
。。。
####【豆包】
。。。
Q:EMUI系统拦截通知栏第一次启动app拦截成功,后续再启动拦截app失败
A:...
在 EMUI 系统(华为定制 Android 系统)中出现 “首次启动拦截成功、后续启动失败” 的问题,核心原因是 EMUI 对 NotificationListenerService 做了专属的后台管控和权限回收机制—— 首次启动时服务临时激活,后续应用重启 / 后台被杀后,EMUI 会直接禁用该服务的运行权限,导致拦截失效。下面我会针对 EMUI 特性给出专属解决方案(Java 实现),彻底解决这个问题。
一、EMUI 拦截失效的核心原因
1.EMUI 后台冻结机制:华为的 “应用启动管理” 默认会将非白名单应用设为 “自动管理”,重启应用后会冻结 NotificationListenerService,导致服务无法注册。
2.权限临时生效:首次授权 NotificationListenerService 后,EMUI 仅让权限在 “当前应用会话” 生效,应用重启后权限被隐性回收,需重新触发权限绑定。
3.服务重启逻辑被拦截:EMUI 会拦截普通的 startService 调用,即使代码中重启服务,也会被系统拒绝执行。
二、EMUI 专属解决方案(Java 实现)
1. 强制绑定 NotificationListenerService 权限(解决权限回收)
EMUI 中仅引导用户到设置页开启权限不够,需在应用重启后主动触发系统重新绑定服务,核心是通过反射调用系统 API 重新授权:
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
public class EMUINotificationBinder {
private static final String TAG = "EMUIBinder";
// EMUI 专属:重新绑定 NotificationListenerService 权限(解决重启后权限失效)
public static void rebindNotificationListenerService(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
return;
}
try {
// 获取系统 NotificationManagerService 的 Binder
IBinder binder = ServiceManager.getService("notification");
if (binder == null) {
Log.e(TAG, "获取 NotificationManagerService Binder 失败");
return;
}
// 构造调用参数:组件名 + 启用状态
ComponentName component = new ComponentName(context.getPackageName(),
MyNotificationListenerService.class.getName());
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.app.INotificationManager");
data.writeString(component.flattenToString());
data.writeInt(1); // 1=启用,0=禁用
// 调用系统 API 重新绑定服务(EMUI 需强制触发)
binder.transact(1008, data, reply, 0); // 1008 是 INotificationManager 的 registerListener 方法码
reply.readException();
Log.d(TAG, "EMUI 重新绑定通知监听服务成功");
data.recycle();
reply.recycle();
} catch (RemoteException | Exception e) {
Log.e(TAG, "EMUI 绑定服务失败:", e);
}
}
// 反射获取 ServiceManager(EMUI 必须)
private static class ServiceManager {
public static IBinder getService(String name) {
try {
Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
return (IBinder) serviceManagerClass.getMethod("getService", String.class)
.invoke(null, name);
} catch (Exception e) {
Log.e(TAG, "反射获取 ServiceManager 失败:", e);
return null;
}
}
}
}
2. 引导用户关闭 EMUI 自动管理(解决后台冻结)
EMUI 的 “应用启动管理” 是核心卡点,需引导用户将应用加入 “手动管理” 并开启 “允许后台活动”,代码如下:
import android.content.Context; import android.content.Intent; import android.os.Build; import android.provider.Settings; import android.util.Log; public class EMUIStartupManagerUtils { private static final String TAG = "EMUIStartup"; // 判断是否为 EMUI 系统 public static boolean isEMUI() { try { Class<?> cls = Class.forName("android.os.SystemProperties"); String emuiVersion = (String) cls.getMethod("get", String.class) .invoke(null, "ro.build.version.emui"); return emuiVersion != null && !emuiVersion.isEmpty(); } catch (Exception e) { return false; } } // 跳转到 EMUI 应用启动管理页面(华为专属) public static void openEMUIStartupManager(Context context) { if (!isEMUI()) { return; } try { // EMUI 不同版本的设置页 Intent 不同,兼容主流版本 Intent intent = new Intent(); intent.setAction("huawei.intent.action.HW_STARTUP_MANAGER_SETTING"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } catch (Exception e) { // 备用方案:跳转到应用信息页 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setData(android.net.Uri.parse("package:" + context.getPackageName())); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); Log.d(TAG, "跳转到应用信息页,需手动找到「启动管理」"); } } // 提示用户开启的配置(需在 UI 中展示) public static String getEMUIConfigTips() { return "请将本应用设置为「手动管理」,并勾选:\n1. 允许自启动\n2. 允许后台活动\n3. 允许关联启动"; } }
3. 改造 NotificationListenerService(适配 EMUI 重启逻辑)
在原有服务基础上,增加 EMUI 专属的重启和绑定逻辑,确保应用重启后服务能重新激活:
import android.app.Notification; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; public class MyNotificationListenerService extends NotificationListenerService { private static final String TAG = "EMUIInterceptor"; @Override public void onCreate() { super.onCreate(); // EMUI 专属:启动前台服务(必须,否则会被立即冻结) startEMUIForegroundService(); // EMUI 专属:重新绑定权限(解决重启后权限失效) EMUINotificationBinder.rebindNotificationListenerService(this); } // EMUI 前台服务强化版(华为要求前台服务必须有可见通知,否则会被判定为违规) private void startEMUIForegroundService() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建华为兼容的通知渠道(必须设为 IMPORTANCE_DEFAULT,否则通知会被隐藏) android.app.NotificationChannel channel = new android.app.NotificationChannel( "emui_notification_interceptor", "通知拦截服务", android.app.NotificationManager.IMPORTANCE_DEFAULT ); android.app.NotificationManager nm = getSystemService(android.app.NotificationManager.class); if (nm != null) { nm.createNotificationChannel(channel); } } // 构建前台服务通知(EMUI 要求必须显示“正在运行”的提示) Notification notification = new Notification.Builder(this) .setChannelId("emui_notification_interceptor") .setSmallIcon(R.mipmap.ic_launcher) // 替换为你的应用图标 .setContentTitle("通知拦截服务运行中") .setContentText("为保证拦截功能正常,请保持后台运行") .setOngoing(true) // 设为不可清除(EMUI 关键) .setPriority(Notification.PRIORITY_DEFAULT) .build(); // 启动前台服务(ID 不能为 0,EMUI 会拒绝) startForeground(1001, notification); } // 核心拦截方法(EMUI 需优先过滤无效通知) @Override public void onNotificationPosted(StatusBarNotification sbn) { super.onNotificationPosted(sbn); // EMUI 中主线程阻塞会直接导致服务被杀死,必须用子线程 new Thread(() -> { try { // 过滤 EMUI 系统保护的通知(如华为推送、前台服务通知) if (sbn == null || sbn.getNotification() == null) return; if ((sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) return; // 获取通知信息(EMUI 中部分应用会隐藏 extras,需兼容) String pkgName = sbn.getPackageName(); Bundle extras = sbn.getNotification().extras; String title = extras.getString(Notification.EXTRA_TITLE, ""); String content = extras.getString(Notification.EXTRA_TEXT, ""); // 示例:拦截微信通知 if ("com.tencent.mm".equals(pkgName) && !TextUtils.isEmpty(content)) { Log.d(TAG, "EMUI 拦截到微信通知:" + title + " - " + content); // EMUI 中取消通知需用兼容方法 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { cancelNotification(sbn.getKey()); } } } catch (Exception e) { Log.e(TAG, "EMUI 拦截失败:", e); } }).start(); } // EMUI 中服务断开后主动重启 @Override public void onListenerDisconnected() { super.onListenerDisconnected(); Log.d(TAG, "EMUI 通知服务断开,尝试重新连接"); // 重新绑定服务(EMUI 专属) EMUINotificationBinder.rebindNotificationListenerService(this); // 重新启动服务 requestRebind(new ComponentName(this, MyNotificationListenerService.class)); } // 应用启动时主动触发服务绑定 public static void startInterceptorService(Context context) { Intent intent = new Intent(context, MyNotificationListenerService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(intent); } else { context.startService(intent); } } }
4. 应用启动页的完整适配逻辑(关键)
在应用的启动 Activity 中,需按以下步骤确保 EMUI 环境下权限和服务稳定:
import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 步骤 1:检测是否为 EMUI 系统
if (EMUIStartupManagerUtils.isEMUI()) {
// 步骤 2:检测通知权限是否开启
if (!NotificationPermissionUtils.isNotificationListenerEnabled(this)) {
NotificationPermissionUtils.openNotificationListenerSettings(this);
Toast.makeText(this, "请开启通知监听权限", Toast.LENGTH_LONG).show();
} else {
// 步骤 3:EMUI 专属:重新绑定权限(解决重启后失效)
EMUINotificationBinder.rebindNotificationListenerService(this);
// 步骤 4:启动拦截服务
MyNotificationListenerService.startInterceptorService(this);
// 步骤 5:引导用户关闭自动管理(首次启动时提示)
Toast.makeText(this, EMUIStartupManagerUtils.getEMUIConfigTips(), Toast.LENGTH_LONG).show();
// 可选:跳转到 EMUI 启动管理页
// EMUIStartupManagerUtils.openEMUIStartupManager(this);
}
} else {
// 非 EMUI 系统的普通逻辑
if (!NotificationPermissionUtils.isNotificationListenerEnabled(this)) {
NotificationPermissionUtils.openNotificationListenerSettings(this);
} else {
MyNotificationListenerService.startInterceptorService(this);
}
}
}
}
MUI 环境下的额外注意事项
必须关闭 “应用启动管理” 的自动管理:这是 EMUI 下最核心的步骤 —— 用户需手动将应用设为「手动管理」,并勾选 “允许自启动、允许后台活动、允许关联启动”,否则服务会被立即冻结。
前台服务通知不能隐藏:EMUI 会检测前台服务的通知是否可见,若设为 IMPORTANCE_LOW 或隐藏,会判定为 “违规前台服务” 并强制停止。
避免频繁重启服务:EMUI 对频繁启动的服务会触发 “恶意行为” 判定,建议仅在应用启动、服务断开时重启。
适配 EMUI 不同版本:华为不同 EMUI 版本(如 EMUI 10/11/12)的设置页路径略有差异,代码中已做兼容,若跳转失败可引导用户手动到「设置 > 应用和服务 > 应用启动管理」操作。
Q:详细介绍Android JAVA中使用车牌识别库HyperLPR详细步骤及例子代码
A:...
Android Java 集成 HyperLPR 车牌识别 超详细完整教程
我给你整理纯 Java 开发、无 Kotlin、可直接运行的 HyperLPR 集成步骤,包含:环境配置 → 资源导入 → 权限配置 → 核心代码 → 相机 / 相册识别示例,复制粘贴就能用。
一、先明确版本
我们用 HyperLPR 最新版(支持绿牌 / 蓝牌 / 黄牌)
底层:MNN 推理引擎
语言:纯 Java
平台:Android
无需联网,本地离线识别
二、完整集成步骤(一步步跟着做)
步骤 1:创建 Android 项目(Java)
新建项目 → 选择 Empty Views Activity
Language 选 Java
Minimum SDK 建议 API 21 (Android 5.0)
步骤 2:下载 HyperLPR Android 资源
下载我整理好的 必备文件包(模型 + so 库 + 工具类):
https://github.com/zeusees/HyperLPR/tree/master/Prj-Android
你只需要复制 3 个部分:
assets 模型文件
jniLibs 架构 so 库
Java 识别工具类 HyperLPR.java
步骤 3:导入 assets 模型文件
在 main 目录上右键 → New → Folder → Assets Folder
将下面 3 个模型文件 复制进去:
det_model.mnn
rec_model.mnn
point_model.mnn
步骤 4:导入 so 库(关键)
在 main 目录下新建文件夹:jniLibs
放入这些架构文件夹:
arm64-v8a
armeabi-v7a
x86
x86_64
不导入会报:UnsatisfiedLinkError 动态库加载失败
步骤 5:导入 HyperLPR Java 工具类
在你的包名下新建类:HyperLPR.java
直接复制下面完整代码(纯 Java,可直接用):
java
运行
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Log;
public class HyperLPR {
private static final String TAG = "HyperLPR";
static {
System.loadLibrary("hyperlpr");
System.loadLibrary("MNN");
}
public native boolean init(AssetManager assetManager,
String detModel,
String recModel,
String pointModel);
public native String plateRecognition(Bitmap bitmap);
public static Bitmap rotateBitmap(Bitmap bitmap, float degrees) {
if (bitmap == null) return null;
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
}
步骤 6:配置 build.gradle(Module 级别)
确保你的 build.gradle 支持 NDK 架构:
gradle
android {
// ...其他配置
defaultConfig {
// ...
minSdk 21
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
// 必须加,否则模型读取失败
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
assets.srcDirs = ['src/main/assets']
}
}
}
步骤 7:配置权限(AndroidManifest.xml)
xml
<!-- 相机 -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<!-- 读写存储 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 网络(可选,仅用于调试) -->
<uses-permission android:name="android.permission.INTERNET" />
Android 6.0+ 必须动态申请权限,代码里会写。
三、核心使用代码(Java 示例)
1. 初始化 HyperLPR(在 Activity 中)
java
运行
private HyperLPR hyperLPR;
private void initHyperLPR() {
hyperLPR = new HyperLPR();
boolean success = hyperLPR.init(getAssets(),
"det_model.mnn",
"rec_model.mnn",
"point_model.mnn");
if (success) {
Log.d("HyperLPR", "初始化成功");
} else {
Log.e("HyperLPR", "初始化失败");
}
}
2. 识别方法(输入 Bitmap → 输出车牌字符串)
java
运行
private String recognizePlate(Bitmap bitmap) {
if (hyperLPR == null || bitmap == null) return "未初始化";
// 识别核心代码(只有一行!)
String plate = hyperLPR.plateRecognition(bitmap);
Log.d("识别结果", "车牌:" + plate);
return plate;
}
四、完整可用 Activity 代码(相册选图识别)
你可以直接替换 MainActivity 运行:
java
运行
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
private HyperLPR hyperLPR;
private ImageView ivPlate;
private TextView tvResult;
private Button btnSelect;
private static final int REQUEST_CODE_IMAGE = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ivPlate = findViewById(R.id.iv_plate);
tvResult = findViewById(R.id.tv_result);
btnSelect = findViewById(R.id.btn_select);
// 1. 初始化车牌识别
initHyperLPR();
// 2. 选择图片识别
btnSelect.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_CODE_IMAGE);
});
}
private void initHyperLPR() {
hyperLPR = new HyperLPR();
boolean ok = hyperLPR.init(getAssets(),
"det_model.mnn",
"rec_model.mnn",
"point_model.mnn");
Log.d("HyperLPR", "初始化状态:" + ok);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_IMAGE && resultCode == RESULT_OK && data != null) {
Uri uri = data.getData();
String path = getImagePathFromUri(uri);
Bitmap bitmap = BitmapFactory.decodeFile(path);
ivPlate.setImageBitmap(bitmap);
// 识别车牌
String plate = hyperLPR.plateRecognition(bitmap);
tvResult.setText("识别结果:" + plate);
}
}
private String getImagePathFromUri(Uri uri) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(uri, projection, null, null, null);
if (cursor == null) return "";
cursor.moveToFirst();
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
cursor.close();
return path;
}
}
对应布局 activity_main.xml
xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<ImageView
android:id="@+id/iv_plate"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="centerInside"
android:background="#eee"/>
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginTop="20dp"/>
<Button
android:id="@+id/btn_select"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="选择车牌图片识别"/>
</LinearLayout>
五、运行效果
点击按钮选择一张车牌照片
自动识别并显示:
示例输出:浙A12345D(绿牌)
示例输出:京A88888(蓝牌)
识别速度:100ms~200ms
六、常见问题(必看)
1. 报错:java.lang.UnsatisfiedLinkError
原因:jniLibs 路径不对 或 so 文件缺失
解决:确保目录结构:
plaintext
src/main/jniLibs/armeabi-v7a/xxx.so
2. 初始化失败
原因:assets 模型文件缺失
解决:必须放入 3 个 .mnn 文件
3. 识别率低
图片模糊 → 识别失败
角度倾斜大 → 可先旋转再识别
光线太暗 → 效果下降
七、我可以继续帮你
如果你需要,我可以直接给你:
相机实时预览识别(Java 完整代码)
相机自动抓拍车牌
带车牌区域框选的 Demo
直接给你 可直接编译运行的完整 Android 工程
Android-SDK示例工程
我们提供了一个Android-SDK相关的Demo工程:hyperlpr3-android-sdk,您可以根据需求去编译动态库使用该项目。
如果你需要快速将我们的sdk集成到你自己的Android项目中,那么你可以将以下依赖添加到项目的build.gradle中:
步骤 1. 将JitPack仓库添加到构建文件中。将其添加到根构建中。在仓库末尾添加Gradle:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
步骤 2. 添加以下依赖
dependencies {
implementation 'com.github.HyperInspire:hyperlpr3-android-sdk:1.0.3'
}
步骤 3. 在应用程序中使用hyperlpr
// 初始化通常在程序初始化时执行,只需执行一次
HyperLPR3.getInstance().init(this, new HyperLPRParameter());
…
// 识别一张图像
Plate[] plates = HyperLPR3.getInstance().plateRecognition(bitmap, HyperLPR3.CAMERA_ROTATION_0, HyperLPR3.STREAM_BGRA);
关于快速集成到安卓工程可以查看: Prj-Android
可识别和待支持的车牌的类型(中文)
支持
单行蓝牌
单行黄牌
新能源车牌
教练车牌
有限支持
白色警用车牌
使馆/港澳车牌
双层黄牌
武警车牌
待支持
民航车牌
双层武警
双层军牌
双层农用车牌
双层个性化车牌
更多国家车牌
Note:由于训练的时候样本存在一些不均衡的问题,一些特殊车牌存在一定识别率低下的问题,如(使馆/港澳车牌),会在后续的版本进行改进。
下一篇:Kotlin学习笔记