高通Android 11/12/13 通过包名设置默认launcher

背景:最近在封装供第三应用系统SDK 接口,遇到一个无法通过包名设置主launcher代码坑所以记录下。
 

涉及类roles.xml # <!---
      ~ @see com.android.settings.applications.defaultapps.DefaultHomePreferenceController
      ~ @see com.android.settings.applications.defaultapps.DefaultHomePicker
      ~ @see com.android.server.pm.PackageManagerService#setHomeActivity(ComponentName, int)
      -->

DeaultAppActivity.java#onCreate

DefaultAppChildFragment.java # onRoleChanged # addPreference

AutoDefaultAppListFragment#onActivityCreated

ManageRoleHolderStateLiveData.java #setRoleHolderAsUser

HandheldDefaultAppFragment.java(packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/handheld)#newInstance

RoleManager.java #addRoleHolderAsUser

IRoleManager.aidl #addRoleHolderAsUser

Role.java  #getDefaultHolders 

TwoTargetPreference.java #OnSecondTargetClickListener

PackageManagerShellCommand.java#runSetHomeActivity

ResolverActivity.java # onCreate

ParseActivityUtils #
    private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,
            ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,
            TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,
            ParseInput input, int parentActivityNameAttr, int permissionAttr,
            int exportedAttr)

1、一开始我是这样写的,代码如下图所示。

private void setDefaultLauncher3(Context context,String packageName,String className) {
     try {
         PackageManager pm = getPackageManager();
         Log.i("deflauncher", "deflauncher : PackageName = " + packageName + " ClassName = " + className);

         IntentFilter filter = new IntentFilter();
         filter.addAction("android.intent.action.MAIN");
         filter.addCategory("android.intent.category.HOME");
         filter.addCategory("android.intent.category.DEFAULT");

         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_HOME);
         List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
         final int N = list.size();
         ComponentName[] set = new ComponentName[N];
         int bestMatch = 0;
         for (int i = 0; i < N; i++) {
             ResolveInfo r = list.get(i);
             set[i] = new ComponentName(r.activityInfo.packageName,
                     r.activityInfo.name);
             if (r.match > bestMatch) bestMatch = r.match;
         }
         ComponentName preActivity = new ComponentName(packageName, className);
         pm.addPreferredActivity(filter, bestMatch, set, preActivity);

     } catch (Exception e) {
         e.printStackTrace();
     }
 }

2、具体添加位置参考在frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java

3、写死launcher包名主activity类名方法如下代码所示 app.olauncher.MainActivity

/**
     * This method shares parsing logic between Activity/Receiver/alias instances, but requires
     * passing in booleans for isReceiver/isAlias, since there's no indicator in the other
     * parameters.
     *
     * They're used to filter the parsed tags and their behavior. This makes the method rather
     * messy, but it's more maintainable than writing 3 separate methods for essentially the same
     * type of logic.
     */
    @NonNull
    private static ParseResult<ParsedActivity> parseActivityOrAlias(ParsedActivity activity,
            ParsingPackage pkg, String tag, XmlResourceParser parser, Resources resources,
            TypedArray array, boolean isReceiver, boolean isAlias, boolean visibleToEphemeral,
            ParseInput input, int parentActivityNameAttr, int permissionAttr,
            int exportedAttr) throws IOException, XmlPullParserException {
        String parentActivityName = array.getNonConfigurationString(parentActivityNameAttr, Configuration.NATIVE_CONFIG_VERSION);
        if (parentActivityName != null) {
            String packageName = pkg.getPackageName();
            String parentClassName = ParsingUtils.buildClassName(packageName, parentActivityName);
            if (parentClassName == null) {
                Log.e(TAG, "Activity " + activity.getName()
                        + " specified invalid parentActivityName " + parentActivityName);
            } else {
                activity.setParentActivity(parentClassName);
            }
        }

        String permission = array.getNonConfigurationString(permissionAttr, 0);
        if (isAlias) {
            // An alias will override permissions to allow referencing an Activity through its alias
            // without needing the original permission. If an alias needs the same permission,
            // it must be re-declared.
            activity.setPermission(permission);
        } else {
            activity.setPermission(permission != null ? permission : pkg.getPermission());
        }

        final boolean setExported = array.hasValue(exportedAttr);
        if (setExported) {
            activity.exported = array.getBoolean(exportedAttr, false);
        }

        final int depth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG
                || parser.getDepth() > depth)) {
            if (type != XmlPullParser.START_TAG) {
                continue;
            }

            final ParseResult result;
            if (parser.getName().equals("intent-filter")) {
                ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,
                        !isReceiver, visibleToEphemeral, resources, parser, input);
                if (intentResult.isSuccess()) {
                    ParsedIntentInfo intent = intentResult.getResult();
                    if (intent != null) {
						Log.e(TAG,"ZM activityName="+activity.getName());
				      if("app.olauncher.MainActivity".equals(activity.getName()))
                           {
                                intent.addCategory("android.intent.category.HOME");
                                intent.addCategory("android.intent.category.DEFAULT");
                                intent.setPriority(1000);
                           }
                        activity.order = Math.max(intent.getOrder(), activity.order);         
                        activity.addIntent(intent);
                        if (LOG_UNSAFE_BROADCASTS && isReceiver
                                && pkg.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
                            int actionCount = intent.countActions();
                            for (int i = 0; i < actionCount; i++) {
                                final String action = intent.getAction(i);
                                if (action == null || !action.startsWith("android.")) {
                                    continue;
                                }

                                if (!SAFE_BROADCASTS.contains(action)) {
                                    Slog.w(TAG,
                                            "Broadcast " + action + " may never be delivered to "
                                                    + pkg.getPackageName() + " as requested at: "
                                                    + parser.getPositionDescription());
                                }
                            }
                        }
                    }
                }
                result = intentResult;
            } else if (parser.getName().equals("meta-data")) {
                result = ParsedComponentUtils.addMetaData(activity, pkg, resources, parser, input);
            } else if (parser.getName().equals("property")) {
                result = ParsedComponentUtils.addProperty(activity, pkg, resources, parser, input);
            } else if (!isReceiver && !isAlias && parser.getName().equals("preferred")) {
                ParseResult<ParsedIntentInfo> intentResult = parseIntentFilter(pkg, activity,
                        true /*allowImplicitEphemeralVisibility*/, visibleToEphemeral,
                        resources, parser, input);
                if (intentResult.isSuccess()) {
                    ParsedIntentInfo intent = intentResult.getResult();
                    if (intent != null) {
                        pkg.addPreferredActivityFilter(activity.getClassName(), intent);
                    }
                }
                result = intentResult;
            } else if (!isReceiver && !isAlias && parser.getName().equals("layout")) {
                ParseResult<ActivityInfo.WindowLayout> layoutResult =
                        parseActivityWindowLayout(resources, parser, input);
                if (layoutResult.isSuccess()) {
                    activity.windowLayout = layoutResult.getResult();
                }
                result = layoutResult;
            } else {
                result = ParsingUtils.unknownTag(tag, pkg, parser, input);
            }

            if (result.isError()) {
                return input.error(result);
            }
        }

        if (!isAlias && activity.launchMode != LAUNCH_SINGLE_INSTANCE_PER_TASK
                && activity.metaData != null && activity.metaData.containsKey(
                ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE)) {
            final String launchMode = activity.metaData.getString(
                    ParsingPackageUtils.METADATA_ACTIVITY_LAUNCH_MODE);
            if (launchMode != null && launchMode.equals("singleInstancePerTask")) {
                activity.launchMode = LAUNCH_SINGLE_INSTANCE_PER_TASK;
            }
        }

        ParseResult<ActivityInfo.WindowLayout> layoutResult =
                resolveActivityWindowLayout(activity, input);
        if (layoutResult.isError()) {
            return input.error(layoutResult);
        }
        activity.windowLayout = layoutResult.getResult();

        if (!setExported) {
            boolean hasIntentFilters = activity.getIntents().size() > 0;
            if (hasIntentFilters) {
                final ParseResult exportedCheckResult = input.deferError(
                        activity.getName() + ": Targeting S+ (version " + Build.VERSION_CODES.S
                        + " and above) requires that an explicit value for android:exported be"
                        + " defined when intent filters are present",
                        DeferredError.MISSING_EXPORTED_FLAG);
                if (exportedCheckResult.isError()) {
                    return input.error(exportedCheckResult);
                }
            }
            activity.exported = hasIntentFilters;
        }

        return input.success(activity);
    }

4、在ResolverActivity.java 中onCreate方法中 执行以下代码,代码路径 /frameworks/base/core/java/com/android/internal/app/ResolverActivity.java


    protected void onCreate(Bundle savedInstanceState, Intent intent,
            CharSequence title, int defaultTitleRes, Intent[] initialIntents,
            List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
        setTheme(appliedThemeResId());
        super.onCreate(savedInstanceState);

        if (mResolvingHome) {
            setDefaultLauncher3();
            finish();
            return;
        }

5、灵活一点如果动态设置launcher流程又不一样,下图是Setttings默认主屏幕应用  launcher列表选项(这个界面radiobutton控件通过preference动态添加 这个addPreference(preference):

6、点击事件位置代码路径packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/DefaultAppChildFragment.java

 private void addPreference(@NonNull String key, @NonNull Drawable icon,
            @NonNull CharSequence title, boolean checked, @Nullable ApplicationInfo applicationInfo,
            @NonNull ArrayMap<String, Preference> oldPreferences,
            @NonNull PreferenceScreen preferenceScreen, @NonNull Context context) {
        TwoStatePreference preference = (TwoStatePreference) oldPreferences.get(key);
        if (preference == null) {
            preference = requirePreferenceFragment().createApplicationPreference(context);
            preference.setKey(key);
            preference.setIcon(icon);
            preference.setTitle(title);
            preference.setPersistent(false);
            preference.setOnPreferenceChangeListener((preference2, newValue) -> false);
            preference.setOnPreferenceClickListener(this);
        }
          Log.e("DefaultAppChildFragment","addPreference");
          preference.setChecked(checked);
	   
        if (applicationInfo != null) {
            mRole.prepareApplicationPreferenceAsUser(preference, applicationInfo, mUser, context);
        }

        preferenceScreen.addPreference(preference);
    }

logcat日志

 DefaultAppChildFragment com.android.permissioncontroller     E  addPreference

7、另外一种通过指令去设置 adb shell pm set-home-activity  app.olauncher.debug (主launcher包名),验证过是没问题的。

8、实际调用还是通过RoleManager#addRoleHolderAsUser方法去添加为主Launcher

代码路径packages\modules\Permission\framework-s\java\android\app\role\RoleManager.java

  /**
     * Add a specific application to the holders of a role. If the role is exclusive, the previous
     * holder will be replaced.
     * <p>
     * <strong>Note:</strong> Using this API requires holding
     * {@code android.permission.MANAGE_ROLE_HOLDERS} and if the user id is not the current user
     * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
     *
     * @param roleName the name of the role to add the role holder for
     * @param packageName the package name of the application to add to the role holders
     * @param flags optional behavior flags
     * @param user the user to add the role holder for
     * @param executor the {@code Executor} to run the callback on.
     * @param callback the callback for whether this call is successful
     *
     * @see #getRoleHoldersAsUser(String, UserHandle)
     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
     *
     * @hide
     */
    @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
    @SystemApi
    public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
            @ManageHoldersFlags int flags, @NonNull UserHandle user,
            @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
        Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
        Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
        Objects.requireNonNull(user, "user cannot be null");
        Objects.requireNonNull(executor, "executor cannot be null");
        Objects.requireNonNull(callback, "callback cannot be null");
        try {
            mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
                    createRemoteCallback(executor, callback));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

打印logcat日志如下所示

2024-05-14 01:18:43.314  1653-1653  RoleManager             pid-1653                             D  Package added as role holder, role: android.app.role.HOME, package: com.android.launcher3
2024-05-14 01:47:11.673  2854-23939 RoleContro...erviceImpl com.android.permissioncontroller     I  Package is already a role holder, package: com.android.launcher3, role: android.app.role.HOME
2024-05-14 01:47:11.674  1653-1653  RoleManager             pid-1653                             D  Package added as role holder, role: android.app.role.HOME, package: com.android.launcher3

2024-05-14 01:18:43.319  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:18:43.324  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep
2024-05-14 01:18:43.332  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:18:43.338  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep
2024-05-14 01:47:10.880  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=app.olauncher.debugtitle=Olauncher
2024-05-14 01:47:10.885  2854-2854  DefaultApp...ragment ZM com.android.permissioncontroller     E  key=com.android.launcher3title=Quickstep

9、代码路径 packages/modules/Permission/PermissionController/src/com/android/permissioncontroller/role/ui/ManageRoleHolderStateLiveData.java

10、代码路径frameworks\base\services\core\java\com/android\server\pm\PackageManagerShellCommand.java

private int runSetHomeActivity() {
        final PrintWriter pw = getOutPrintWriter();
        int userId = UserHandle.USER_SYSTEM;
        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "--user":
                    userId = UserHandle.parseUserArg(getNextArgRequired());
                    break;
                default:
                    pw.println("Error: Unknown option: " + opt);
                    return 1;
            }
        }

        String pkgName;
        String component = getNextArg();
        if (component.indexOf('/') < 0) {
            // No component specified, so assume it's just a package name.
            pkgName = component;
        } else {
            ComponentName componentName =
                    component != null ? ComponentName.unflattenFromString(component) : null;
            if (componentName == null) {
                pw.println("Error: invalid component name");
                return 1;
            }
            pkgName = componentName.getPackageName();
        }
        final int translatedUserId =
                translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");
        final CompletableFuture<Boolean> future = new CompletableFuture<>();
        try {
            RoleManager roleManager = mContext.getSystemService(RoleManager.class);
            roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName, 0,
                    UserHandle.of(translatedUserId), FgThread.getExecutor(), future::complete);
            boolean success = future.get();
            if (success) {
                pw.println("Success");
                return 0;
            } else {
                pw.println("Error: Failed to set default home.");
                return 1;
            }
        } catch (Exception e) {
            pw.println(e.toString());
            return 1;
        }
    }

11、最后可以把这些代码添加自己自定义系统服务AIDL接口 ,然后在Android.bp中添加源码编译路径(不知道怎么添加AIDL源码编译路径看我之前这篇文章高通 Android 12 源码编译aidl接口_安卓12 怎么写aidl-CSDN博客)

12、在自己app应用调用通过 如下代码 进行设置即可(Process导入android.os包切记哈)

/**
     * 设置当前Launcher
     *
     * @param packageName 传入第三方launcher包名
     */
    public void setCurrentLauncher(String packageName) {
        setRoleHolderAsUser(RoleManager.ROLE_HOME, packageName, 0, Process.myUserHandle(), mContext);

    }

13、最后别忘记如果你是app调用代码的时候记得加系统签名哈 AndroidManifest.xml中 ,否则也不会生效。

 android:sharedUserId="android.uid.system"

到这里基本结束了,转载请注明出处高通Android 11/12/13 通过包名设置默认launcher-CSDN博客,谢谢!

感谢

Android R设置默认桌面_setroleholderasuser-CSDN博客

Android10.0(Q) 默认应用设置(电话、短信、浏览器、主屏幕应用)_android.app.role.browser-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Git 基础使用(2) 分支管理

文章目录 分支概念分支使用查看分支分支创建分支切换分支合并合并冲突分支删除 分支管理快进模式分支策略内容保存错误处理 分支概念 &#xff08;1&#xff09;分支概念 Git分支是指在版本控制系统Git中&#xff0c;用来表示项目的不同工作流程或开发路径的一个重要概念。通过…

海豚调度器如何看工作流是在哪个worker节点执行

用海豚调度器&#xff0c;执行一个工作流时&#xff0c;有时成功&#xff0c;有时失败&#xff0c;怀疑跟worker节点环境配置不一样有关。要怎样看是在哪个worker节点执行&#xff0c;在 海豚调度器 Web UI 中&#xff0c;您可以查看任务实例&#xff0c;里面有一列显示host&a…

从零开始详解OpenCV条形码区域分割

前言 在识别二维码之前&#xff0c;首先要划分出二维码的区域&#xff0c;在本篇文章中将从零开始实现二维码分割的功能&#xff0c;并详细介绍用到的方法。 我们需要处理的图像如下&#xff1a; 完整代码 首先我们先放出完整代码&#xff0c;然后根据整个分割流程介绍用到…

windows 使用 workerman

简单示例 workerman从3.5.3版本开始已经能够同时支持linux系统和windows系统。 1、需要PHP>5.4&#xff0c;并配置好PHP的环境变量。 2、Windows版本的Workerman不依赖任何扩展。 3、安装使用以及使用限制这里。 4、由于Workerman在Windows下有诸多使用限制&#xff0c…

【万字面试题】Redis

文章目录 常见面试题布隆过滤器原理和数据结构&#xff1a;特点和应用场景&#xff1a;缺点和注意事项&#xff1a;在python中使用布隆过滤器 三种数据删除策略LRU (Least Recently Used)工作原理&#xff1a;应用场景&#xff1a; LFU (Least Frequently Used)工作原理&#x…

vs2019 c++中模板 enable_if_t 的使用

&#xff08;1&#xff09; 该模板的定义如下&#xff1a; template <bool _Test, class _Ty void> struct enable_if {}; // no member "type" when !_Testtemplate <class _Ty> struct enable_if<true, _Ty> { // type is _Ty for _Testusing …

OSEK应用模式

1 前言 应用模式&#xff08;Application modes)用于区分不同的场景&#xff0c;以便在系统运行时&#xff0c;组织各自相互独立的OS相关的资源集合&#xff0c;是一种分而治之的思想体现。不同的应用模式是互斥的&#xff0c;即系统当前必须在一种应用模式&#xff08;且只能在…

OV SSL证书的特点

OV SSL证书&#xff0c;全称为Organization Validation SSL Certificate&#xff08;组织验证型SSL证书&#xff09;&#xff0c;是一种中级的SSL证书类型。与仅验证域名所有权的DV&#xff08;Domain Validation&#xff09;证书不同&#xff0c;OV证书在颁发前会执行更加严格…

01.认识HTML及常用标签

目录 URL&#xff08;统一资源定位系统&#xff09; HTML&#xff08;超文本标记语言&#xff09; 1&#xff09;html标签 2&#xff09;head标签 3&#xff09;title标签 4&#xff09;body标签 标签的分类 DTD文档声明 基础标签 1&#xff09;H系列标签 2&#xff09…

C++基础与深度解析 | 语句 | 分支语句 | 循环语句 | 达夫设备

文章目录 一、语句基础二、分支语句1.分支语句--if2.分支语句--switch 三、循环语句1.循环语句--while2.循环语句--do-while3.循环语句--for4.循环语句--基于范围的for循环5.break / continue语句四、语句的综合应用--达夫设备 一、语句基础 语句的常见类别&#xff1a; 表达…

如何在 Ubuntu 12.10 上使用 Python 创建 Nagios 插件

介绍 Python 是一种在 Linux 上默认可用的流行命令处理器。 我们之前已经介绍过如何在 Ubuntu 12.10 x64 上安装 Nagios 监控服务器。 这一次&#xff0c;我们将扩展这个想法&#xff0c;使用 Python 创建 Nagios 插件。 这些插件将在客户 VPS 上运行&#xff0c;并通过 NR…

树莓派|角速度和加速度传感器

角速度传感器和加速度传感器是常见的惯性传感器&#xff0c;常用于测量物体的旋转和线性运动。 角速度传感器&#xff08;Gyroscope&#xff09;用于测量物体绕三个轴&#xff08;X、Y、Z&#xff09;的旋转速度或角速度。它可以提供关于物体在空间中的旋转方向和角度变化的信…

数据结构学习/复习14--归并排序的递归与循环实现/计数排序

一、归并排序 1.递归实现 注意事项&#xff1a;即使排序的数字个数不为2的倍数也可正常分解&#xff0c;其思想没有规定一定要左右数目对称才可合并 注意事项&#xff1a;归并的思想还适用于外排序 2.递归改循环 注意事项&#xff1a;边界处理与非2的n次方倍的处理 版本1&…

win10下,svn上传.so文件失败

问题&#xff1a;win10下使用TortoiseSVN&#xff0c;svn上传.so文件失败 解决&#xff1a;右键&#xff0c;选择Settings&#xff0c;Global ignore pattern中删除*.so&#xff0c;保存即可。

网络3--网络通信的深度理解(端口号)

网络通信的进一步理解 两个主机间进行通信&#xff0c;其实是两个主机间的软件进行通信&#xff0c;软件也就是可执行程序&#xff0c;运行时就是进程&#xff0c;所以也为进程间通信。 进程间通信需要共享资源&#xff0c;这里两个主机间的共享资源是网络&#xff0c;利用的是…

指针(4)

1. 字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* ; 一般使用: int main() {char i a;char* p &i;*p q;printf("%c", i);return 0; } 然后我们看这个例子,这是把⼀个字符串放到pstr指针变量里了吗&#xff1f; 事实上不是,他只是将…

如何管理多个版本的Node.js

我们如何在本地管理多个版本的Node.js&#xff0c;有没有那种不需要重新安装软件再修改配置文件和环境变量的方法&#xff1f;经过我的查找&#xff0c;还真有这种方式&#xff0c;那就是nvm&#xff08;Node Version Manager&#xff09;。 下面我就给大家介绍下NVM的使用 1…

笔记本黑屏,重新开机主板没有正常运作的解决办法

拆开笔记本后壳&#xff0c;打开看到主板&#xff0c;将主板上的这颗纽扣电池拆下来&#xff0c;如果是带连接线的&#xff08;如下图&#xff09;&#xff0c;可以将接口处线头拔出&#xff0c;等1分钟再把线接上。 ------------- 以下是科普 首先&#xff0c;电脑主板上的这…

Llama-Factory + Ollama 打造属于自己的中文版 Llama3

Meta 推出 Llama3 也有一小段时间了。Llama3 包含 8B 和 70B 两种参数规模&#xff0c;涵盖预训练和指令调优的变体。Llama 3 支持多种商业和研究用途&#xff0c;并已在多个行业标准测试中展示了其卓越的性能&#xff08;关于Llama3的具体介绍可以参考本站另外一篇博文&#x…

详解xlsxwriter 操作Excel的常用API

我们知道可以通过pandas 对excel 中的数据进行处理分析&#xff0c;但是pandas本身对格式化数据方面提供了很少的支持&#xff0c;如果我们想对pandas进行数据分析后的数据进行格式化相关操作&#xff0c;我们可以使用xlsxwriter&#xff0c;本文就对xlsxwriter的常见excel格式…