Android 源码中 内置系统App(整个APP源码方式集成)

1. 如何新建一个系统 App 项目

使用 Android Studio 新建一个空项目 FirstSystemApp,包名设置为 com.yuandaima.firstsystemapp,语言选择 Java。后面为叙述方便称该项目为 as 项目。

接着在 jelly/rice14 目录下创建如下的目录和文件:

接着将 as 项目中的 res 文件下的资源文件拷贝到 Jelly/Rice14/FirstSystemApp/res 中,把 as 项目中的 MainActivity.java 拷贝到 Jelly/Rice14/FirstSystemApp/src/com/yuandaima/firstsystemapp 中。

接着修改已添加的 AndroidManifest.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.yuandaima.firstsystemapp"><applicationandroid:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/Theme.FirstSystemApp"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-dataandroid:name="android.app.lib_name"android:value="" /></activity></application></manifest>

接着修改已添加的 Android.bp 文件:

android_app {name: "FirstSystemApp",srcs: ["src/**/*.java"],resource_dirs: ["res"],manifest: "AndroidManifest.xml",platform_apis: true,sdk_version: "",certificate: "platform",product_specific: true,//依赖static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout"],}

至此我们的系统 App 就创建好了。

接着在我们的 Product 中添加这个App,修改 device/Jelly/Rice14/Rice14.mk

# 添加以下内容
PRODUCT_PACKAGES += FirstSystemApp

接着编译系统,启动虚拟机,打开 app:

source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator 

2. 系统 App 与 普通 App 的差异

2.1 系统 App 可以使用更多的 api

当我们在 Android.bp 中配置了:

platform_apis: true,
sdk_version: "",

当 platform_apis 为 true 时,sdk_version 必须为空。这种情况下我们的 app 会使用平台 API 进行编译而不是 SDK,这样我们的 App 就能访问到非 SDK API 了。关于 SDK API 和非 SDK API 的内容可以参考官方文档

2.2 系统 App 的签名

AOSP 内置了 apk 签名文件,我们可以在 Android.bp 中通过 certificate 配置系统 app 的签名文件,certificate 的值主要有一下几个选项:

  • testkey:普通 apk,默认情况下使用
  • platform:该 apk 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的 APK 所在进程的 UID 为system
  • shared:该 apk 需要和 home/contacts 进程共享数据
  • media:该 apk 是 media/download 系统中的一环
  • PRESIGNED:表示 这个 apk 已经签过名了,系统不需要再次签名;

2.3 系统 App 能使用更多的权限

当 Android.bp 中的 privileged 被配置为 true 时,我们的系统 App 在添加特许权限许可名单后,能使用 signatureOrSystem 级别的权限,而普通 App 是不能使用这些权限的。

2.4 系统 App 能更轻松地实现进程保活

三方 App 为了不被杀掉,可以说是用尽了千方百计。保活对于系统 App 其实是非常简单的:

在 AndroidManifest.xml 中添加如下参数即可:

<applicationandroid:persistent="true">

3. 系统 App 添加依赖

1. 添加 AOSP 中已有的库

在 FirstSystemApp 的 Android.bp 中我们添加了很多依赖:

    static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout"],

在 AOSP 中, 很多常用的库均以预编译模块的方式添加到系统源码中。比如常用的 AndroidX 库定义在 prebuilts/sdk/current/androidx 目录下。这些库通过 prebuilts/sdk/current/androidx/Android.bp 引入。比如 recyclerview 库的引入方式如下:

android_library {name: "androidx.recyclerview_recyclerview",sdk_version: "31",apex_available: ["//apex_available:platform","//apex_available:anyapex",],min_sdk_version: "14",manifest: "manifests/androidx.recyclerview_recyclerview/AndroidManifest.xml",static_libs: ["androidx.recyclerview_recyclerview-nodeps","androidx.annotation_annotation","androidx.collection_collection","androidx.core_core","androidx.customview_customview",],java_version: "1.7",
}

可以看到引入的是一个 android_library,名字叫 androidx.recyclerview_recyclerview。maifest 文件在 manifests/androidx.recyclerview_recyclerview/ 目录下,进入这个目录只有一个 AndroidManifest.xml 文件,其内容如下:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="androidx.recyclerview" ><uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="28" /></manifest>

很奇怪,并没有看到 RecyclerView 库的源码,也没有看到 aar 库文件。我们接着看 Android.bp 中的依赖,其中一项是 androidx.recyclerview_recyclerview-nodeps,我们在 Android.bp 中看一下它的引入方式:

android_library_import {name: "androidx.recyclerview_recyclerview-nodeps",aars: ["m2repository/androidx/recyclerview/recyclerview/1.1.0-alpha07/recyclerview-1.1.0-alpha07.aar"],sdk_version: "current",min_sdk_version: "14",static_libs: ["androidx.annotation_annotation","androidx.collection_collection","androidx.core_core","androidx.customview_customview",],
}

这里看到了,它的 aar 库在这里: m2repository/androidx/recyclerview/recyclerview/1.1.0-alpha07/recyclerview-1.1.0-alpha07.aar

继续查阅我们可以发现,prebuilts/tools/common/m2 目录下引入了大量的三方库。

总结一下,当我们的系统 App 需要引入一个库的时候,通常会在 prebuilds 目录下查找:

  • androidx 相关库引入,先在 prebuilts/sdk/current/androidx 下寻找配置好的 bp 文件
  • 其他库引入,先在 prebuilts/tools/common/m2 下寻找寻找配置好的 bp 文件

都没有,就得自己引入了

2. 自己给 AOSP 添加库

2.1 java 库源码引入

https://blog.csdn.net/a546036242/article/details/136845033

2.2 java 库以 jar 包形式引入

https://blog.csdn.net/a546036242/article/details/136845033

2.3 Android 库源码引入

device/Jelly/Rice14 目录下创建如下的文件和文件夹

其中 MyCustomView.java 是一个用于演示的没有具体功能的自定义 View:

package com.yuandaima.firstsystemandroidlibrary;import android.content.Context;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;public class MyCustomView extends View {public MyCustomView(Context context) {super(context);}public MyCustomView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}
}

AndroidManifest.xml 的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.yuandaima.firstsystemandroidlibrary"></manifest>

Android.bp 的内容如下:

android_library  {name: "FirstSystemAndroidLibrary",srcs: ["src/**/*.java"],resource_dirs: ["res"],manifest: "AndroidManifest.xml",sdk_version: "current",product_specific: true,//依赖static_libs: ["androidx.appcompat_appcompat",],java_version: "1.7",installable: true,}

接着修改我们的 FirstSystemApp 项目

Android.bp 添加依赖如下:

android_library  {//......//依赖static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout","FirstSystemAndroidLibrary"],}

修改一下 MainActivity,在 App 里使用我们的自定义 View:

package com.yuandaima.firstsystemapp;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import com.yuandaima.firstsystemandroidlibrary.MyCustomView;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyCustomView myView = new MyCustomView(this);}
}

接着编译系统,启动虚拟机,打开 app:

source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator 

这样我们的库就算引入完毕了。

2.4 Android 库以 aar 包形式引入

更多的时候 Android 库是以 aar 包的形式引入。

假设我们的 FirstSystemApp 需要引入 lottie 这个动画库。

首先我们这里下载好 lottie 库的 aar 打包文件。

device/Jelly/Rice14 目录下创建如下的目录结构:

liblottie/
├── Android.bp
└── lottie-5.2.0.aar

其中 Android.bp 的内容如下:

android_library_import {name: "lib-lottie",aars: ["lottie-5.2.0.aar"],sdk_version: "current",
}

然后我们修改 FirstSystemApp 中的 Android.bp 引入这个库:

static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout","FirstSystemAndroidLibrary","lib-lottie"],

这样就可以在 App 中使用 lottie 库了

3. JNI 项目

3.1 创建 JNI 项目

Android 10 下,Android.bp(soong) 方式对 JNI 的支持有点问题,所以我们只有用 Android.mk 来演示了。Android 13 下 Android.bp (soong) 是完美支持 JNI 的。

device/Jelly/Rice14 目录下添加如下的文件与文件夹:

jni/Android.mk 内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optional# This is the target being built.
LOCAL_MODULE:= myjnilib# All of the source files that we will compile.
LOCAL_SRC_FILES:= \native.cpp# All of the shared libraries we link against.
LOCAL_LDLIBS := -llog# No static libraries.
LOCAL_STATIC_LIBRARIES :=LOCAL_CFLAGS := -Wall -WerrorLOCAL_NDK_STL_VARIANT := noneLOCAL_SDK_VERSION := currentLOCAL_PRODUCT_MODULE := trueinclude $(BUILD_SHARED_LIBRARY)

jni/native.cpp 的内容如下:

/** Copyright (C) 2008 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#define LOG_TAG "simplejni native.cpp"
#include <android/log.h>#include <stdio.h>#include "jni.h"#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)static jint
add(JNIEnv* /*env*/, jobject /*thiz*/, jint a, jint b) {
int result = a + b;ALOGI("%d + %d = %d", a, b, result);return result;
}static const char *classPathName = "com/example/android/simplejni/Native";static JNINativeMethod methods[] = {{"add", "(II)I", (void*)add },
};/** Register several native methods for one class.*/
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* gMethods, int numMethods)
{jclass clazz;clazz = env->FindClass(className);if (clazz == NULL) {ALOGE("Native registration unable to find class '%s'", className);return JNI_FALSE;}if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {ALOGE("RegisterNatives failed for '%s'", className);return JNI_FALSE;}return JNI_TRUE;
}/** Register native methods for all classes we know about.** returns JNI_TRUE on success.*/
static int registerNatives(JNIEnv* env)
{if (!registerNativeMethods(env, classPathName,methods, sizeof(methods) / sizeof(methods[0]))) {return JNI_FALSE;}return JNI_TRUE;
}// ----------------------------------------------------------------------------/** This is called by the VM when the shared library is first loaded.*/typedef union {JNIEnv* env;void* venv;
} UnionJNIEnvToVoid;jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{UnionJNIEnvToVoid uenv;uenv.venv = NULL;jint result = -1;JNIEnv* env = NULL;ALOGI("JNI_OnLoad");if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {ALOGE("ERROR: GetEnv failed");goto bail;}env = uenv.env;if (registerNatives(env) != JNI_TRUE) {ALOGE("ERROR: registerNatives failed");goto bail;}result = JNI_VERSION_1_4;bail:return result;
}

SimpleJNI.java 的内容如下:


package com.example.android.simplejni;import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;public class SimpleJNI extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView tv = new TextView(this);int sum = Native.add(2, 3);tv.setText("2 + 3 = " + Integer.toString(sum));setContentView(tv);}
}class Native {static {// The runtime will add "lib" on the front and ".o" on the end of// the name supplied to loadLibrary.System.loadLibrary("simplejni");}static native int add(int a, int b);
}

最外面的 Android.mk 的内容如下:

TOP_LOCAL_PATH:= $(call my-dir)# Build activityLOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-subdir-java-files)LOCAL_PACKAGE_NAME := JNIAppLOCAL_JNI_SHARED_LIBRARIES := myjnilibLOCAL_PROGUARD_ENABLED := disabledLOCAL_SDK_VERSION := currentLOCAL_DEX_PREOPT := falseLOCAL_PRODUCT_MODULE := trueinclude $(BUILD_PACKAGE)# ============================================================# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))

AndroidManifest.xml 的内容如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.android.simplejni"><application android:label="Simple JNI"><activity android:name="SimpleJNI"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest> 

最后在 device/Jelly/Rice14/Rice14.mk 中添加:

PRODUCT_PACKAGES += helloworld \JNIApp \

编译并运行虚拟机就可以看到 JNIApp 了:

3.2 JNIApp 链接自定义库

我们这里尝试修改 JNIApp,让其引用到我们的 libmymath 库。

修改 JNIApp/jni/Android.mk:

# 添加以下内容
LOCAL_SHARED_LIBRARIES := libmymath

修改 JNIApp/jni/native.cpp:

#include "my_math.h"static jint
add(JNIEnv* /*env*/, jobject /*thiz*/, jint a, jint b) {int result = a + b;result = my_add(result, result);ALOGI("%d + %d = %d", a, b, result);return result;
}

然后编译系统,发现报以下错误:

error: myjnilib (native:ndk:none:none) should not link to libmymath (native:platform)

可以看出是编译平台不一致导致的,修改 JNIApp/jni/Android.mk:

# 下面这行注释掉即可
# LOCAL_SDK_VERSION := current

最后重新编译,执行虚拟机即可

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

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

相关文章

金江能源:助力新能源行业发展上市之路逐步迈进

在当今全球节能减排的大背景下,新能源产业成为了社会发展的热门领域。楚雄州金江能源集团有限公司作为新能源产业中的佼佼者,凭借其雄厚的技术实力和前瞻性的发展战略,已经展开了公司上市的蓄势之路。5月15日,金江能源将在港交所上市,为公司的发展注入更多资金和资源。 作为一…

vue axios 缓存 接口请求实现缓存加载

文章写的多了&#xff0c;开头就不知道怎么写了&#xff0c;硬挤一些句子总觉的卖弄。其实更多的想留下各位看官&#xff0c;多多的点赞&#xff0c;多多的关注&#xff0c;多的收藏。为将来的博客化动作做好前期数据粉丝基础。哦哦哦&#xff0c;我在想啥呢。。这大下午的。。…

xAI开发的一款巨大型语言模型(HLM)--Grok 1

在xAI发布Grok的权重和架构之后&#xff0c;很明显大型语言模型&#xff08;LLM&#xff09;的时代已经过去&#xff0c;现在是巨大型语言模型&#xff08;HLM&#xff09;的时代。这个混合专家模型发布了3140亿个参数&#xff0c;并且在Apache 2.0许可下发布。这个模型没有针对…

【项目管理后台】Vue3+Ts+Sass实战框架搭建一

项目管理后台 建立项目最好是卸载Vetur 新建.env.d.ts文件安装Eslint安装校验忽略文件添加运行脚本 安装prettier新建.prettierrc.json添加规则新建.prettierignore忽略文件 安装配置stylelint新建.stylelintrc.cjs 添加后的运行脚本配置husky配置commitlint配置husky 强制使用…

从服务器到云原生:企业IT基础设施的演进之路

随着数字经济的迅猛发展&#xff0c;企业IT数字化转型已成为推动业务创新和提升竞争力的关键。在这一转型过程中&#xff0c;基础设施的建设与升级显得尤为重要。企业需要不断优化和更新他们的基础设施&#xff0c;以适应不断变化的市场需求和技术发展。本文将探讨企业IT数字化…

信息系统项目管理师020:信息安全(2信息技术发展—2.1信息技术及其发展—2.1.4信息安全)

文章目录 2.1.4 信息安全1.信息安全基础2.加密解密3.安全行为分析技术4.网络安全态势感知 2.1.4 信息安全 常见的信息安全问题主要表现为&#xff1a;计算机病毒泛滥、恶意软件的入侵、黑客攻击、利用计算机犯罪、网络有害信息泛滥、个人隐私泄露等。随着物联网、云计算、人工智…

【JVM】如何判断堆上的对象没有被引用?

如何判断堆上的对象没有被引用&#xff1f; 常见的有两种判断方法&#xff1a;引用计数法和可达性分析法。 引用计数法会为每个对象维护一个引用计数器&#xff0c;当对象被引用时加1&#xff0c;取消引用时减1。 引用计数法的缺点-循环引用 引用计数法的优点是实现简单&…

大数据面试题 —— HBase

目录 什么是HBase简述HBase 的数据模型HBase 的读写流程HBase 在写的过程中的region的split的时机HBase 和 HDFS 各自的使用场景HBase 的存储结构HBase 中的热现象&#xff08;数据倾斜&#xff09;是怎么产生的&#xff0c;以及解决办法有哪些HBase rowkey的设计原则HBase 的列…

RAFT: Adapting Language Model to Domain Specific RAG

RAFT: Adapting Language Model to Domain Specific RAG 相关链接&#xff1a;arXiv GitHub 关键字&#xff1a;Retrieval-Augmented Fine Tuning (RAFT)、Large Language Models (LLMs)、Domain Specific RAG、Distractor Documents、Chain-of-Thought 摘要 预训练大型语言模…

云原生:重塑未来应用的基石

随着数字化时代的不断深入&#xff0c;云原生已经成为了IT领域的热门话题。它代表着一种全新的软件开发和部署范式&#xff0c;旨在充分利用云计算的优势&#xff0c;并为企业带来更大的灵活性、可靠性和效率。今天我们就来聊一聊这个热门的话题&#xff1a;云原生~ &#x1f4…

Android Studio实现内容丰富的安卓自行车租赁平台

获取源码请点击文章末尾QQ名片联系&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动 项目编号105 1.开发环境android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看公告 3.查看自行车分类 4.预订自行车&#xff0c; 5.…

【高效开发工具系列】语雀Excel入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

前端项目,个人笔记(三)【Vue-cli - api封装-axios使用举例】

目录 前言 1、axios配置与测试 1.1、配置 1.2、测试 2、使用axios案例-渲染header 3、Pinia优化重复请求 3.1、为什么&#xff1f; 3.2、使用Pinia优化代码步骤 步骤一&#xff1a;在main.js中创建 Pinia 实例&#xff0c;并将其作为插件添加到 Vue 应用中 步骤二&am…

初识数据库|数据库的特点、分类以及作用

数据库系统&#xff08;DateBase System&#xff0c;简称DBS&#xff09;是指在计算机系统中引入数据库后的系统构成&#xff0c;由计算机硬件&#xff0c;操作系统&#xff0c;DBMS&#xff0c;DB&#xff0c;应用程序和用户以及数据库开发和管理人员等组成。 &#xff08;一…

[BT]BUUCTF刷题第一天(3.19)

第一天&#xff08;共4题&#xff09; Web [极客大挑战 2019]EasySQL Payload&#xff1a; 用户名&#xff1a;admin or 11# &#xff08;密码也可以改成这个&#xff09; 密码&#xff1a;1&#xff08;可任意&#xff09; 网站漏洞代码&#xff1a; sql"select *…

Android和IOS Flutter应用开发使用 Provider.of 时,可以使用 listen: false 来避免不必要的重建

文章目录 listen: false解释示例 listen: false 使用 Provider.of 时&#xff0c;可以使用 listen: false 来避免不必要的重建 解释 当您使用 Provider.of 获取状态对象时&#xff0c;默认情况下&#xff0c;该对象每次发生变化时都会触发重建该对象所在的组件。这在大多数情…

云平台一键迁移(腾讯云windos服务器迁移到阿里云windos服务器)

参考文档 https://help.aliyun.com/zh/smc/use-cases/one-click-cloud-platform-migration 迁移文档 https://cloud.tencent.com/document/product/598/37140 #腾讯密钥创建 https://cloud.tencent.com/document/product/1340/51945 安装腾讯云自动化服务助手 一.导入迁移…

GitHub gpg体验

文档 实践 生成新 GPG 密钥 gpg --full-generate-key查看本地GPG列表 gpg --list-keys关联GPG公钥与Github账户 gpg --armor --export {key_id}GPG私钥对Git commit进行签名 git config --local user.signingkey {key_id} # git config --global user.signingkey {key_id} git…

JVM常用垃圾收集器

JVM 4.1 哪些对象可以作为GC ROOT? 虚拟机栈&#xff08;栈帧中的局部变量表&#xff09;中引用的对象本地方法栈中引用的对象方法区静态变量引用的对象方法区常量引用的对象被同步锁持有的对象JNI&#xff08;Java Native Interface&#xff09;引用的对象 4.2 常用垃圾收集…

计算机二级(Python)真题讲解每日一题:《方菱形》

描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬ 请写代码替换横线&#xff0…