RK3576-Android15-整合PackageInstaller达成静默安装功能

news/2026/1/17 16:32:12/文章来源:https://www.cnblogs.com/gccbuaa/p/19496511

提示:Android15-整合PackageInstaller实现静默安装功能

文章目录

  • 前言
  • 一、 需求
  • 二、参考资料
  • 三、文件修改
  • 四、实现方案
    • 1、InstallStart - onCreate 方法中-判断是否拦截进行静默安装-拷贝文件
    • 2、SilenceInstallReceiver 接收静默安装广播请求-进行静默安装业务
    • 3、静默安装核心工具类-SilenceInstallManager
    • 4、PackageInstallerApplication 初始化静默安装工具
    • 5、AndroidManifest 配置 广播组件
  • 五、实验验证-进行静默安装测试
  • 六、拓展思路-讨论
  • 总结


前言

在RK 平台 Android15 上面做静默安装功能

一、 需求

在Android15 上面实现静默安装功能,不要用脚本实现,借助包安装器PackageInstaller 来实现。

二、参考资料

MTK-Android13-包安装器PackageInstaller 静默安装实现
    本文笔记完全参考之前知识点 MTK平台Android13 版本思想,在安装器App-PackageInstaller 基础上更改部分流程实现静默安装功能。

Android15-解决后台无法启动应用App问题 静默安装成功后 有 是否直接启动的参数,这个业务在Android15 中无法后台启动App,这里有修改方案


    针对PM 安装流程、PackageInstaller 安装流程,如果有需要强烈建议如下知识篇 相关知识点。 对 安装流程、PackageInstaller 安装等知识面和业务流程有非常全面的介绍。

RK-Android11-PackageInstaller安装器自动安装功能实现 魔改PackageInstaller 去掉各种状态跳转,自定义一个界面一个带进度界面安装实现。
Rk3576-Android15-Apk 安装基本知识点和Apk安装拦截功能实现 Framework层 安装过程流程分析
拦截adb install/uninstall安装 - 安装流程分析 命令脚本安装流程分析
PMS安装apk之界面跳转 这个是对 PackageInstaller 安装器安装流程,界面跳转流程分析

三、文件修改

包安装前 PackageInstaller 目录:/frameworks/base/packages/PackageInstaller
新增文件:

src/com/android/packageinstaller/SilenceInstallManager.java
src/com/android/packageinstaller/SilenceInstallReceiver.java

修改文件:

AndroidManifest.xml
src/com/android/packageinstaller/InstallStart.java
src/com/android/packageinstaller/PackageInstallerApplication.java
src/com/android/packageinstaller/UninstallerActivity.java

在这里插入图片描述

四、实现方案

1、InstallStart - onCreate 方法中-判断是否拦截进行静默安装-拷贝文件

InstallStart 入口onCreate 方法中,拦截,是否进行静默安装,如果是,那么就进行静默安装逻辑,拷贝文件。拦截正常的安装流程。

// modify by fangchen start
// if silence install  ->to silence install
if (intent.getBooleanExtra(SilenceInstallReceiver.SILENCE_INSTALL_KEY, false)) {
Log.d(TAG," StagingAsyncAppTask  to  execute ");
StagingAsyncAppTask mStagingTask = new StagingAsyncAppTask(intent.getBooleanExtra(SilenceInstallReceiver.IS_LAUNCH_KEY, false));
mStagingTask.execute(getIntent().getData());
return;
}
// modify by fangchen end

拷贝 文件资源代码如下:

@SuppressLint("NewApi")
private final class StagingAsyncAppTask extends AsyncTask<Uri, Void, File> {private boolean mIsLaunch;public StagingAsyncAppTask(boolean isLaunch){mIsLaunch = isLaunch;}@Overrideprotected File doInBackground(Uri... params) {Log.d(TAG, "===========copy file from user app start");if (params == null || params.length <= 0) {return null;}Uri packageUri = params[0];try (InputStream in = getContentResolver().openInputStream(packageUri)) {// Despite the comments in ContentResolver#openInputStream the returned stream can// be null.if (in == null) {return null;}File mStagedFile = TemporaryFileManager.getStagedFile(InstallStart.this);try (OutputStream out = new FileOutputStream(mStagedFile)) {byte[] buffer = new byte[1024 * 1024];int bytesRead;while ((bytesRead = in.read(buffer)) >= 0) {// Be nice and respond to a cancellationout.write(buffer, 0, bytesRead);}}return mStagedFile;} catch (IOException | SecurityException | IllegalStateException e) {Log.w(TAG, "Error staging apk from content URI", e);}return null;}@Overrideprotected void onPostExecute(File installFile) {if (null != installFile) {// Now start the installation again from a fileLog.d(TAG, "copy file from user app finish");Intent installIntent = new Intent(SilenceInstallReceiver.SILENCE_INSTALL_APP);installIntent.putExtra(SilenceInstallReceiver.APP_URI_KEY, Uri.fromFile(installFile));installIntent.putExtra(SilenceInstallReceiver.IS_LAUNCH_KEY, mIsLaunch);installIntent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);installIntent.setPackage("com.android.packageinstaller");sendBroadcast(installIntent);Log.d(TAG, "send to install");} else {Log.d(TAG, "copy file from user app fail");}finish();}}

2、SilenceInstallReceiver 接收静默安装广播请求-进行静默安装业务

如上,在进行安装初期InstallStart 中 判断当前进行静默后,广播开始通知进行静默安装

package com.android.packageinstaller;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class SilenceInstallReceiver extends BroadcastReceiver {
public static final String SILENCE_INSTALL_APP = "com.android.packageinstaller.ACTION_SILENCE_INSTALL";
public static final String SILENCE_INSTALL_KEY = "silence_install";
public static final String IS_LAUNCH_KEY = "is_launch";
public static final String APP_URI_KEY = "app_uri";
private static final String TAG = "SilenceInstallReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.w(TAG, "SilenceInstallReceiver getAction---->" + intent.getAction());
if (SILENCE_INSTALL_APP.equals(intent.getAction())) {
Uri uri = intent.getParcelableExtra(APP_URI_KEY);
boolean isLaunch = intent.getBooleanExtra(IS_LAUNCH_KEY, false);
SilenceInstallManager.getInstance(context).silenceInstall(uri, isLaunch);
}
}
}

3、静默安装核心工具类-SilenceInstallManager

假使对安装流程有相关的了解和掌握,我个人经验就是两点:

  • 文件的拷贝,uri 的传递,按照规范传递参数拼凑数据
  • 进行Session 处理,提交 到Framework 层 进行安装。
  • 对于安装回调进度,注册Session回调而已
package com.android.packageinstaller;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.ArrayMap;
import android.util.Log;
import androidx.annotation.NonNull;
import android.content.ActivityNotFoundException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import android.os.ParcelFileDescriptor;
import android.content.res.AssetFileDescriptor;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.content.ActivityNotFoundException;
final class SilenceInstallManager {
private static final String TAG = "SilenceInstallManager";
private static final int MSG_WHAT_INSTALL_FINISH_SUCCESS = 0;
private static final int MSG_WHAT_INSTALL_FINISH_FAIL = 1;
private static final int MSG_WHAT_UNINSTALL_COMPLETE = 2;
private Context mContext;
@SuppressLint("NewApi")
private ArrayMap<Integer, InstallAppInfo> InstallAppInfoMap = new ArrayMap<>();private @Nullable PackageInstaller mInstaller;private static volatile SilenceInstallManager INSTANCE;private SilenceInstallManager(Context context) {mContext = context;mInstaller = mContext.getPackageManager().getPackageInstaller();}public static SilenceInstallManager getInstance(Context context) {if (null == INSTANCE) {synchronized (SilenceInstallManager.class) {if (null == INSTANCE) {INSTANCE = new SilenceInstallManager(context.getApplicationContext());}}}return INSTANCE;}@SuppressLint("NewApi")private PackageInstaller.SessionCallback mSessionCallback = new PackageInstaller.SessionCallback() {@Overridepublic void onCreated(int sessionId) {Log.d(TAG, "onCreated---->" + sessionId);}@Overridepublic void onBadgingChanged(int sessionId) {Log.w(TAG, "mSessionCallback onBadgingChanged---->" + sessionId);}@Overridepublic void onActiveChanged(int sessionId, boolean active) {Log.w(TAG, "mSessionCallback onActiveChanged---->" + sessionId + "  active--->" + active);}@Overridepublic void onProgressChanged(int sessionId, float progress) {Log.w(TAG, "mSessionCallback onProgressChanged---->" + sessionId + "  progress--->" + progress);}@Overridepublic void onFinished(int sessionId, boolean success) {Log.d(TAG, "onFinished---->" + sessionId + "  success--->" + success);Message msg = Message.obtain();msg.what = MSG_WHAT_INSTALL_FINISH_SUCCESS;msg.arg1 = sessionId;msg.obj = success;mHandler.sendMessage(msg);}};@SuppressLint("HandlerLeak")private Handler mHandler = new Handler() {@Overridepublic void dispatchMessage(@NonNull Message msg) {mInstaller.unregisterSessionCallback(mSessionCallback);if (msg.what == MSG_WHAT_INSTALL_FINISH_SUCCESS) {boolean result = (boolean) msg.obj;int sessionId = msg.arg1;InstallAppInfo info = InstallAppInfoMap.remove(sessionId);if (result) {Log.d(TAG, "install success");if (null != info) {if (info.isLaunch && null != info.info && null != info.info.packageName && !"".equals(info.info.packageName)) {launchApp(info.info.packageName);}File f = new File(info.filePath);if (f.exists()) {f.delete();}}} else {Log.d(TAG, "install fail===========111111111111111===");}} else if (msg.what == MSG_WHAT_INSTALL_FINISH_FAIL) {int sessionId = msg.arg1;if (sessionId != -1) {InstallAppInfoMap.remove(sessionId);}Log.d(TAG, "install fail===========00000000000000000===");} else if (msg.what == MSG_WHAT_UNINSTALL_COMPLETE) {Log.d(TAG, "uninstall complete--->" + msg.arg1);if (msg.arg1 == PackageManager.DELETE_SUCCEEDED) {Log.d(TAG, "delete succeeded");} else {Log.d(TAG, "delete fail");}}}};// public void silenceInstall(String appFilePath, boolean launch) {public void silenceInstall(Uri uri,  boolean launch) {String appFilePath=uri.getPath();if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {mInstaller.registerSessionCallback(mSessionCallback);PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);params.setInstallAsInstantApp(false);params.setInstallReason(PackageManager.INSTALL_REASON_USER);File file = new File(appFilePath);if (!file.exists()) {Log.d(TAG,"=====silenceInstall wenjian not exists======appFilePath:"+appFilePath);sendFailMsg(-1);return;}final AssetFileDescriptor afd = openAssetFileDescriptor(uri);final Uri packageUri =uri;// getIntent().getData();ParcelFileDescriptor pfd = afd != null ? afd.getParcelFileDescriptor() : null;if (pfd != null) {Log.d(TAG,"===========pfd != null=================");try {String debugPathName=  packageUri.toString();final PackageInstaller.InstallInfo result = mInstaller.readInstallInfo(pfd,debugPathName, 0);params.setAppPackageName(result.getPackageName());params.setInstallLocation(result.getInstallLocation());params.setSize(result.calculateInstalledSize(params, pfd));params.setSize(file.length());}catch (Exception e) {Log.e(TAG, "Cannot parse package " + file + ". Assuming defaults.");Log.e(TAG,"Cannot calculate installed size " + file + ". Try only apk size.");params.setSize(file.length());}}else{Log.d(TAG,"===========pfd  ====== null=================");}try {PackageInfo mPkgInfo = PackageUtil.getPackageInfo(mContext, file, PackageManager.GET_PERMISSIONS);int mSessionId =mInstaller.createSession(params);InstallAppInfo installAppInfo = new InstallAppInfo(mSessionId, appFilePath, mPkgInfo, launch);InstallAppInfoMap.put(mSessionId, installAppInfo);InstallingAsyncTask mInstallingTask = new InstallingAsyncTask(mContext, appFilePath, mSessionId);mInstallingTask.execute();} catch (IOException e) {e.printStackTrace();Log.d(TAG,"============InstallingAsyncTask execute failed ==============");sendFailMsg(-1);}}}public  AssetFileDescriptor openAssetFileDescriptor(Uri uri) {try {return  mContext.getContentResolver().openAssetFileDescriptor(uri, "r");} catch (Exception e) {Log.d(TAG, "========Failed to open asset file descriptor", e);return null;}}private void sendFailMsg(int sessionId) {Message msg = Message.obtain();msg.what = MSG_WHAT_INSTALL_FINISH_FAIL;msg.arg1 = sessionId;mHandler.sendMessage(msg);}@SuppressLint("NewApi")private final class InstallingAsyncTask extends AsyncTask<Void, Void,PackageInstaller.Session> {private Context mContext;private String mAppPath;private int mSessionId;public InstallingAsyncTask(Context context, String appPath, int sessionId) {mContext = context;mAppPath = appPath;mSessionId = sessionId;}@Overrideprotected PackageInstaller.Session doInBackground(Void... params) {PackageInstaller.Session session;try {session = mInstaller.openSession(mSessionId);} catch (IOException e) {return null;}session.setStagingProgress(0);try {File file = new File(mAppPath);long totalRead = 0;try (InputStream in = new FileInputStream(file)) {long sizeBytes = file.length();try (OutputStream out = session.openWrite("PackageInstaller", 0, sizeBytes)) {byte[] buffer = new byte[1024 * 1024];while (true) {int numRead = in.read(buffer);if (numRead == -1) {session.fsync(out);break;}if (isCancelled()) {session.close();break;}out.write(buffer, 0, numRead);if (sizeBytes > 0) {/* float fraction = ((float) numRead / (float) sizeBytes);session.addProgress(fraction);*/totalRead += numRead;float fraction = ((float) totalRead / (float) sizeBytes);session.setStagingProgress(fraction);//   publishProgress((int) (fraction * 100.0));}}}}return session;} catch (IOException | SecurityException e) {Log.e(TAG, "Could not write package", e);session.close();return null;}}@Overrideprotected void onPostExecute(PackageInstaller.Session session) {if (session != null) {Intent broadcastIntent = new Intent();PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,1,broadcastIntent,// PendingIntent.FLAG_UPDATE_CURRENT);//  PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);//   PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLEPendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE |PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT);session.commit(pendingIntent.getIntentSender());session.close();Log.d(TAG, "send install PendingIntent----->");} else {mInstaller.abandonSession(mSessionId);Log.d(TAG,"============session error =======mSessionId");sendFailMsg(mSessionId);File f = new File(mAppPath);if (f.exists()) {f.delete();}Log.e(TAG, "copy fail delete file----->");}mContext = null;mAppPath = "";mSessionId = -1;}}private class InstallAppInfo {private int sessionId;private String filePath;private PackageInfo info;private boolean isLaunch;public InstallAppInfo(int sessionId, String filePath, PackageInfo info, boolean isLaunch) {this.sessionId = sessionId;this.filePath = filePath;this.info = info;this.isLaunch = isLaunch;}public int getSessionId() {return sessionId;}public String getFilePath() {return filePath;}public PackageInfo getInfo() {return info;}public boolean isLaunch() {return isLaunch;}}private void launchApp(String appPackageName) {Log.d(TAG,"=======launchApp========appPackageName:"+appPackageName);Intent mLaunchIntent = mContext.getPackageManager().getLaunchIntentForPackage(appPackageName);if (mLaunchIntent != null) {Log.d(TAG, "launch app--->  appPackageName:"+appPackageName);if (mLaunchIntent.resolveActivity(mContext.getPackageManager()) != null) {Log.d(TAG, "launch app--->  startActivity ");try {mLaunchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);mContext.startActivity(mLaunchIntent);} catch (ActivityNotFoundException | SecurityException e) {Log.e(TAG, "Could not start activity", e);}} else {Log.e(TAG, "No activity found to handle the intent for: " + appPackageName);}}else{Log.d(TAG,"===============qidong failed========");}}public void silenceUninstall(String packageName) {Log.i(TAG, "silenceUninstall--->" + packageName);// PackageDeleteObserver observer = new PackageDeleteObserver();// mContext.getPackageManager().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);}/* private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {public void packageDeleted(String packageName, int returnCode) {Message msg = mHandler.obtainMessage(MSG_WHAT_UNINSTALL_COMPLETE);msg.arg1 = returnCode;msg.obj = packageName;mHandler.sendMessage(msg);}}*/}

4、PackageInstallerApplication 初始化静默安装工具

SilenceInstallManager.getInstance(this);

在这里插入图片描述

5、AndroidManifest 配置 广播组件

<!-- modify by fangchen start  --><receiver android:name=".SilenceInstallReceiver"android:exported="true"><intent-filter android:priority="1"><action android:name="com.android.packageinstaller.ACTION_SILENCE_INSTALL" /></intent-filter></receiver><!-- modify by fangchen end  -->

五、实验验证-进行静默安装测试

这里可以传递两个参数:

  • 是否静默安装 silence_install,如果否 则走默认的安装器安装方式
  • 安装成功后是否自启动 is_launch

备注说明:在实际业务中,如果下载成功 软件包 文件 apk,后直接调用当前业务代码即可实现。

val aPath ="/data/data/com.fish.togetsn/files" + File.separator + "bilibili.apk"
Log.d(TAG," aPath path:"+aPath);
val appFile = File(aPath)
if (!appFile.exists()) {
//showToast("请在" + getExternalFilesDir(null)!!.absolutePath + File.separator + "目录中放置升级文件")
ToastUtils.showShort("请 配置文件")
return@setOnClickListener
}
//大于7.0使用此方法
val apkUri = FileProvider.getUriForFile(
ContextProvider.get().context,
"com.fish.togetsn.fileProvider",
appFile
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val installApkIntent = Intent()
installApkIntent.setAction(Intent.ACTION_VIEW)
installApkIntent.addCategory(Intent.CATEGORY_DEFAULT)
installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
installApkIntent.setDataAndType(apkUri, "application/vnd.android.package-archive")
installApkIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
//设置静默安装标识
installApkIntent.putExtra("silence_install", true)
installApkIntent.setPackage("com.android.packageinstaller")
//设置安装完成是否启动标识
installApkIntent.putExtra("is_launch", true)
//设置后台中启动activity标识
// installApkIntent.putExtra("allowed_Background", true)
if (packageManager.queryIntentActivities(installApkIntent, 0).size > 0) {
startActivity(installApkIntent)
}
}

六、拓展思路-讨论

  • 这里模仿的是下载软件成功后,借用 系统自带安装前PackageInstaller 实现。 其中拷贝文件是在入口InstallStart 这个Activity中实现的,那么实际上 我自己把这部分代码实现,也就是拷贝文件实现,直接发送广播给安装器进行安装业务不行吗?
  • 如上 思考,我们使用了PackageInstaller 的入口InstallStart 这个Activity,屏幕会闪一下,实际过程中这个如果避免达到无感?
  • 这里都是在借助PackageInstaller 这个包实现的,比如我们设置com.android.packageinstaller 指定的包名进行application/vnd.android.package-archive 业务,实际上 静默安装和非静默安装混在一起的, 那么就不能分离开来直接在Framework层的Service 服务中实现吗? 这里先给出答案,绝对可行。
  • 其实静默安装 不管哪一个版本都有自己的一套,比如开机第一次 会内置apk, 把这个业务流程单独提出来不也是一个思路吗。

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1174097.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026年终总结PPT新宠:ChatPPT凭何登顶工具榜?

2026年终总结PPT新宠&#xff1a;ChatPPT凭何登顶工具榜&#xff1f; 进入2026年&#xff0c;职场人年终总结、年度汇报PPT制作已彻底进入“AI主导”时代。而在众多AI生成工具中&#xff0c;塔猫ChatPPT&#xff08;或简称ChatPPT&#xff0c;常被本土用户亲切称为“塔猫”&am…

佳木斯市桦南桦川汤原英语雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

在全球化教育浪潮推动下,雅思考试已成为佳木斯市及下属桦南、桦川、汤原地区学子出国深造的核心门槛,优质的雅思培训则是实现高分目标、顺利衔接留学的关键支撑。当前,该区域雅思培训市场呈现多元化发展态势,但多数…

资阳雁江乐至安岳英语雅思辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 老周说教育

近年来,资阳雁江、乐至、安岳等区域留学需求持续攀升,雅思成绩作为海外院校申请的核心语言凭证,成为学子及家长重点关注的关键环节。当前资阳优质雅思培训资源分布不均,乐至、安岳等县域区域优质资源稀缺,本地学子…

市场人别慌:AI写文案,你负责“读懂人心”

AI文案革命与测试人员的机遇 在数字化营销浪潮中&#xff0c;AI文案生成工具&#xff08;如ChatGPT、Jasper等&#xff09;正以惊人的速度改变市场行业。数据显示&#xff0c;2025年全球AI文案市场规模已突破百亿美元&#xff0c;企业纷纷采用AI自动生成广告标语、社交媒体内容…

编程语言禅:从C的“制心一处”到Python的“心无所住” - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2026年智能语音机器人品牌实测推荐 - 速递信息

在数字化转型进入深水区的2026年,智能语音机器人已不再是企业客户服务中的“可选项”,而是降本增效、提升竞争力的“战略必需品”。据统计,部署优质语音机器人的企业,其客服成本可能降低约70%,首次问题解决率提升…

对BAT1节点_STA方法的处理之从ACPI!RestartCtxtPassive到ACPI!StartTimeSlicePassive

对BAT1节点_STA方法的处理之从ACPI!RestartCtxtPassive到ACPI!StartTimeSlicePassive 1: kd> g Breakpoint 37 hit eax899b0024 ebx00000000 ecx899b0024 edx00000000 esi899b0024 edi89985178 eipf741f8c9 espf791aae8 ebpf791ab18 iopl0 nv up ei pl zr na pe nc …

2026 年深圳香港包车公司最新推荐榜单:结合协会测评与多维度分析,选出跨境出行放心之选机场接送/商务接待/旅游包车/出行/跨境/跨境出行服务/粤港澳深圳香港包车公司推荐 - 品致汇

引言 随着粤港澳大湾区跨境出行需求逐年攀升,深圳香港包车市场乱象仍存,为精准筛选优质服务商,本次榜单由广东省汽车租赁行业协会全程参与测评指导,结合近一年市场数据及 3000 + 用户调研结果生成。测评采用 “四维…

2026年温度保险丝厂家推荐:惠州市凯森电子代理UMI内桥65℃/72℃/电饭煲/电水壶等全系产品 - 品牌推荐官

在电子元器件领域,温度保险丝作为关键的安全保护元件,被广泛应用于家电、工业设备及新能源领域。据行业数据显示,2025年全球温度保险丝市场规模达12.3亿美元,其中中国市场占比超35%,年复合增长率保持在8.2%以上。…

深度测评!8款一键生成论文工具:本科生毕业论文写作全攻略

深度测评&#xff01;8款一键生成论文工具&#xff1a;本科生毕业论文写作全攻略 推荐2&#xff1a;「Grammarly」&#xff08;学术版&#xff09;——英文论文润色标杆&#xff08;推荐指数&#xff1a;★★★★☆&#xff09; "对于需要撰写英文论文的本科生&#xff0c…

【AI 学习】揭开AI卷积神经网络的神秘面纱:从理论到实战

【AI学习】揭开卷积神经网络&#xff08;CNN&#xff09;的神秘面纱&#xff1a;从理论到实战&#xff08;2026年最实用版本&#xff09; 这可能是你2026年最值得花3~5小时认真学一遍的AI基础内容&#xff0c;因为&#xff1a; 即使到了今天&#xff0c;大模型时代&#xff0c…

2025年济南大学计算机考研复试机试真题(附 AC 代码 + 解题思路)

2025年济南大学计算机考研复试机试真题 2025年济南大学计算机考研复试上机真题 历年济南大学计算机考研复试上机真题 历年济南大学计算机考研复试机试真题 更多学校题目开源地址&#xff1a;https://gitcode.com/verticallimit1/noobdream N 诺 DreamJudge 题库&#xff1…

2026年主动/驱动/低压/转向/电机/花键/导向轴推荐:无锡源霖时代精密机械全系供应 - 品牌推荐官

在工业制造领域,轴类零件作为机械传动系统的核心组件,其性能直接影响设备运行的稳定性与效率。据统计,2025年全球轴类零件市场规模达1200亿元,其中主动轴、驱动轴等精密轴件占比超45%。无锡源霖时代精密机械有限公…

AI生成HTML原型导入Axure全攻略!

AI生成HTML原型导入Axure全攻略&#xff01;&#xff08;2026年最新实用版&#xff09; 2026年&#xff0c;AI生成高保真HTML原型已经非常成熟&#xff08;v0.dev、bolt.new、Cursor、Replit Agent、Gamma等工具一键出现代UI页面&#xff09;&#xff0c;但Axure RP作为交互逻…

2026年河南专业NFC果汁代加工厂家排名,浩明饮品实力上榜 - 工业品牌热点

在健康饮品消费升级的浪潮中,NFC果汁凭借无添加、原果直榨的核心优势成为市场新宠,而专业的代加工服务则是品牌抢占赛道的关键。面对鱼龙混杂的代工厂,如何找到技术过硬、售后完善的合作伙伴?以下结合行业类型,为…

好“屏”如潮!itc保伦股份再度蝉联行家极光奖LED显示屏非上市公司十强! - 资讯焦点

近日,“2025行家极光奖”在深圳重磅揭晓。今年,“行家极光奖”共揭晓15个榜单,全方位展示LED显示产业链优秀企业的绰约风采,为行业树立标杆,也为下游厂商选购产品提供重要参考依据。 “行家极光奖”是行家说开创…

DeepSeek-V4即将发布,100条DeepSeek高级指令技巧,速速收藏

DeepSeek-V4就要来了&#xff0c;想要真正发挥DeepSeek的全部潜力&#xff1f;这100条精心设计的进阶指令将帮你解锁AI助手的深度能力&#xff0c;涵盖工作、学习、创作、生活全场景&#xff0c;每条都可直接复制使用&#xff01;一、高效工作场景&#xff08;25条&#xff09;…

【Java】Spring Cloud 微服务架构入门:五大核心组件与分布式系统搭建

【Java】Spring Cloud 微服务架构入门&#xff1a;五大核心组件与分布式系统搭建&#xff08;2026年实用版&#xff09; 2026年&#xff0c;Spring Cloud 生态已经非常成熟&#xff0c;虽然Netflix OSS 部分组件早已停止维护&#xff08;如 Eureka 2.0、Hystrix、Ribbon、Zuul…

2026年薄膜开关厂家实力推荐:东莞市创铭电子科技,pet/亚克力/轻触/PC/PVC薄膜开关全品类供应 - 品牌推荐官

在电子元器件领域,薄膜开关凭借其轻薄、耐用、可定制化等特性,成为工业控制、家用电器、医疗设备等场景的核心组件。据行业数据显示,2025年全球薄膜开关市场规模已突破35亿美元,年复合增长率达6.8%,其中中国占比超…

达州通川达川万源宣汉开江大竹渠县英语雅思辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 老周说教育

随着达州通川、达川等主城区及万源、宣汉、开江、大竹、渠县等县域留学需求的持续升温,雅思成绩作为海外院校申请的核心语言凭证,成为众多学子留学路上的关键门槛。然而,达州优质雅思教学资源多集中于通川、达川主城…