下个自主shell蛋
创始人
2024-09-26 17:54:32
0

学个damn!

给我狠狠玩好嘛别卷我啊

知道的是图书馆,不知道的还以为开演唱会呢!

八点啊,那可是八点,才八点!

762a6189b796421095427f0a76cbe942.jpg

不是哥们下午两点半开馆即满人啊我靠?

只能去儿童区学我说不是?

 

别拷打我了我真碎了哥

说说自主shell编写吧(要不然进程控制不白学了)

自主shell首先得有打印命令行提示符吧,命令行提示符构成是这样的:用户名+主机名+当前所处路径,我们都封装成函数:

const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }

分别获取到了对应的字符串,我们还需要一个函数把这些字符串拼接起来,这个功德圆满的函数就是:sprintf!

sprintf是个怎样的函数呢?

sprintf是一个可以向内存空间写入的printf

而snprintf是给定大小的更安全的向内存空间中写入的printf(写到缓冲区)

void MakeCommandLine(char line[], size_t size) { 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, size, "[%s@%s %s]#", username, hostname, cwd); 	fflush(stdout); }

搞完哩, ,,

命令行已经输出了,我们需要获取用户的命令 

而像ls -a -l -i这种命令本质上是字符串嘞,不能直接用scanf获取,因为scanf空格作为分割,但是我们输入命令是不知道有多少空格的输入,按照行获取有木有?

有哇,fgets啊

为何偏偏是它 

 乐意,,,

#include #include #include #include #include  #define SIZE 512  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	char* s = fgets(usercommand, sizeof(usercommand), stdin); 	if (s == NULL) 	{ 		return 1; 	} 	printf("echo:%s\n", usercommand); 	return 0; }

为什么这多输出了一个空行(因为多有了一个\n啊)

为了剔除这个\n,可以这样干:

#include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0'  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	char* s = fgets(usercommand, sizeof(usercommand), stdin); 	if (s == NULL) 	{ 		return 1; 	} 	usercommand[strlen(usercommand) - 1] = ZERO; 	printf("echo:%s\n", usercommand); 	return 0; }

 写成接口就是:

int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }

 接下来需要做的是命令行字符串分割

我们无需再进行手搓函数,有个函数已经提供了分割的功能了:strtok

字符串函数们的使用和模拟实现-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/chestnut_orenge/article/details/135351316 这样赋值,先判断,分割后strtok会返回NULL,刚好让gArgv的最后一个元素是NULL,并且while判断结束

void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }

命令行字符串分割后要执行相应的命令,但是我们不能让该程序执行(代码替换完之后就无了),所以要创建紫禁城帮助我们执行相应的命令

之前学过exec相关函数,我们所获得的命令串都是系统中的,所以默认去环境变量中寻找即可(带p的),又因为获取的是命令串,所以要带v的(容器)

现在大致是这样的:

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  int main() { 	MakeCommandLine();  	char usercommand[SIZE]; 	GetUserCommand(usercommand, sizeof(usercommand)); 	 	splitCommand(usercommand, sizeof(usercommand));  	for (int i = 0; gArgv[i]; i++) 	{ 		printf("gArgv[%d]:%s\n", i, gArgv[i]); 	}  	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id,&status,0); 		if (rid > 0) 		{ 			 		} 	} 	return 0; }

但是我们自己编写的这个shell只能运行一次,我们想要让它一直运行执行命令 

于是封装+循环写个简单的shell就好:

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		GetUserCommand(usercommand, sizeof(usercommand));  		splitCommand(usercommand, sizeof(usercommand));  		ExecuteCommand(); 	} 	return 0; }

大致没问题,但是有个命令跑起来有问题:cd 

 

我们的shell没法进行路径的切换和回退 

每个进程都会记录自己当前所处的路径(父进程有,紫禁城也有)

紫禁城确实是执行了路径切换的命令,但是和父进程没什么关系,而打印命令行是父进程负责的

我们需要让cd交给父进程去执行,也就是所谓的内建命令

所以我们在执行命令前要检查是否是内建命令,由于命令已经被分割,所以直接检查

在获取完用户命令后,进行切换命令需要用到系统调用的接口chdir

 写完了一串代码,会发现cd倒是能用,只不过命令行打印不正常罢了,所以这意味着我们需要对环境变量进行更新

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  void Die() {  }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }  char* gArgv[NUM];  void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

 需要注意的是,我们需要刷新环境变量,以保证出来的都是绝对路径

 改完之后除了cd -不支持,其他都支持(cd -需要保存最近一次所处路径)

#include #include #include #include #include #include #include  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd(); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, cwd); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

插个眼我很好奇为什么编译不过去

我们自己创建的shell在打印命令行的时候保存的是一串路径,但是正常的shell在保存路径的时候只会保存当前路径,那应该怎么办捏?

就是设个指针让它前移,但是需要做一些特殊处理,在一般情况下打印路径分割符后的内容,在特殊情况下只打印路径分隔符

使用宏是因为要单独对指针进行操作 

用do...while(0)是因为可以形成代码块,且do...while(0)后面可加;

在使用时可当做函数,且可应对分支情况的出现

然后还需要接着判断其他的内建命令

#include #include #include #include #include #include #include  #define SkipPath(p) do{ p += (strlen(p) - 1); while (*p != '/')p--;}while(0)  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32   char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd();  	SkipPath(cwd); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{  		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

判断echo命令

 

 这是记录最近一次的返回值(echo $?)啊麻烦死了自己实现shell

忙活半天只能做个青春版,还不能查历史输入的命令

#include #include #include #include #include #include #include  #define SkipPath(p) do{ p += (strlen(p) - 1); while (*p != '/')p--;}while(0)  #define SIZE 512 #define ZERO '\0' #define SEP " " #define NUM 32  int lastcode = 1; char cwd[SIZE * 2]; char* gArgv[NUM];  void Die() { 	exit(1); }  const char* Home() { 	const char* home = getenv("HOME"); 	if (home == NULL) 	{ 		return "/"; 	} 	return home; }  void Cd() { 	const char* path = gArgv[1]; 	if (path == NULL) 	{ 		path = Home(); 	} 	chdir(path); 	char temp[SIZE * 2]; 	getcwd(temp, sizeof(temp)); 	snprintf(cwd, sizeof(cwd), "PWD=%s", temp); 	putenv(cwd); }  const char* GetUserName() { 	const char* name = getenv("USER"); 	if (name == NULL) 	{ 		return "None"; 	} 	return name; }  const char* GetHostName() { 	const char* hostname = getenv("HOSTNAME"); 	if (hostname == NULL) 	{ 		return "None"; 	} 	return hostname; }  const char* GetCwd() { 	const char* cwd = getenv("PWD"); 	if (cwd == NULL) 	{ 		return "None"; 	} 	return cwd; }  void MakeCommandLine() { 	char line[SIZE]; 	const char* username = GetUserName(); 	const char* hostname = GetHostName(); 	const char* cwd = GetCwd();  	SkipPath(cwd); 	snprintf(line, sizeof(line), "[%s@%s %s]#", username, hostname, strlen(cwd) == 1 ? "/" : cwd + 1); 	printf("%s", line); 	fflush(stdout); }  int GetUserCommand(char command[], size_t n) { 	char* s = fgets(command, n, stdin); 	if (s == NULL) 	{ 		return -1; 	} 	command[strlen(command) - 1] = ZERO; 	return strlen(command); }   void splitCommand(char command[], size_t n) { 	gArgv[0] = strtok(command, SEP); 	int index = 1; 	while ((gArgv[index++] = strtok(NULL, SEP))); }  void ExecuteCommand() { 	pid_t id = fork(); 	if (id < 0) 	{ 		Die(); 	} 	else if (id == 0) 	{ 		execvp(gArgv[0], gArgv); 		exit(errno); 	} 	else 	{ 		int status = 0; 		pid_t rid = waitpid(id, &status, 0); 		if (rid > 0) 		{ 			lastcode = WEXITSTATUS(status); 			if (lastcode != 0) 			{ 				printf("%s:%s:%d\n", gArgv[0], strerror(lastcode), lastcode); 			} 		} 	} }  int CheckBuildin() { 	int yes = 0; 	const char* enter_cmd = gArgv[0]; 	if (strcmp(enter_cmd, "cd") == 0) 	{ 		yes = 1; 		Cd(); 	} 	else if (strcmp(enter_cmd, "echo") == 0 && strcmp(gArgv[1], "$?") == 0) 	{ 		yes = 1; 		printf("%d\n", lastcode); 		lastcode = 0; 	} 	return yes; }  int main() { 	int quit = 0; 	while (!quit) 	{ 		MakeCommandLine();  		char usercommand[SIZE]; 		int n = GetUserCommand(usercommand, sizeof(usercommand)); 		if (n < 0) 		{ 			return 1; 		}  		splitCommand(usercommand, sizeof(usercommand));  		n = CheckBuildin(); 		if (n) 		{ 			continue; 		}  		ExecuteCommand(); 	} 	return 0; }

 在shell中建立环境变量表也是默认创建指针

是一个缓冲区,可以自己申请,环境变量表是char* env[32],而定义开个空间就直接自己设置就好:

char** env = (char*)malloc(sizeof(char*)*32);

 自己写个shell就对它怎样执行命令认识的更加深刻了

相关内容

热门资讯

安卓系统降级教程图片,图片解析... 手机用久了,是不是觉得安卓系统越来越卡,想回到那个流畅如丝的年代?别急,今天就来教你怎么给安卓系统来...
安卓系统设置桌面布局,打造个性... 你有没有发现,手机桌面乱糟糟的,看着都头疼?别急,今天就来教你如何巧妙地设置安卓系统的桌面布局,让你...
安卓怎么设置谷歌系统,这里不提... 你有没有想过,你的安卓手机里藏着一个小小的谷歌世界?没错,就是那个全球最流行的操作系统——安卓,它其...
安卓系统甩位软件,轻松导航新体... 你有没有发现,手机里的安卓系统越来越智能了?这不,最近我发现了一个超级好用的甩位软件,简直让我爱不释...
安卓系统接入固态硬盘,速度与稳... 你有没有想过,你的安卓手机或者平板,是不是也能像电脑一样,装上固态硬盘,瞬间提升速度和存储空间呢?今...
rx5 安卓系统,功能解析与使... 你有没有发现,现在汽车界也开始玩起了智能科技?没错,我说的就是那款风头正劲的rx5,它搭载的安卓系统...
安卓系统不待机app,安卓系统... 你有没有遇到过这种情况?手机电量明明还充足,可是一转眼就“嗖”地电量就见底了。这可不是什么好兆头,尤...
苹果系统QQ关联安卓系统QQ,... 你知道吗?最近在社交圈里,大家都在热议一个话题:苹果系统的QQ竟然和安卓系统的QQ关联上了!这可真是...
康佳安卓电视刷系统,焕新体验 亲爱的电视迷们,你是否曾为家里的康佳安卓电视系统卡顿而烦恼?别急,今天我要给你带来一份特别的攻略,让...
荣耀安装安卓原生系统,深度体验... 你知道吗?最近荣耀手机界可是掀起了一股热潮,那就是——荣耀安装安卓原生系统!这可不是什么小打小闹,而...
安卓系统怎么修改dns,轻松提... 你是不是也和我一样,对安卓系统的DNS修改充满了好奇?想要让你的手机上网速度飞起来,或者想要更安全地...
ios王者到安卓系统,探索全新... 你知道吗?最近我可是经历了一场大变身呢!从iOS王者到安卓系统,这其中的转变可真是让我大开眼界。今天...
鸿蒙4.0降级安卓系统,轻松回... 你知道吗?最近科技圈可是炸开了锅,因为华为的新操作系统鸿蒙4.0竟然可以降级到安卓系统!这听起来是不...
电视能装安卓系统,安卓系统助力... 你有没有想过,家里的老电视其实也可以焕发第二春呢?没错,就是那个陪伴你度过无数个夜晚的老电视,现在它...
安卓系统怎样删除文件,轻松掌握... 手机里的文件越来越多,是不是感觉内存都要不够用了?别急,今天就来教你怎么在安卓系统里轻松删除文件,让...
ios怎么运行安卓系统,iOS... 亲爱的果粉们,你是否曾想过,在你的iPhone上也能体验到安卓系统的魅力呢?没错,今天就要来揭秘一个...
安卓系统导航的功能,便捷操作与... 你有没有发现,现在手机里的安卓系统导航功能越来越强大了?简直就像是个贴心的导航小助手,带你穿梭在城市...
店铺管家安卓系统下载,提升运营... 你有没有想过,拥有一款能帮你轻松管理店铺的安卓系统,是不是就像拥有了超级助手呢?没错,今天就要给你介...
安卓系统打开花呗,享受便捷支付... 你有没有发现,现在手机里的安卓系统越来越智能了,各种功能层出不穷。今天,我就来给你详细介绍怎么在安卓...
安卓5.0系统怎么root,安... 亲爱的安卓用户们,你是否曾梦想过让你的手机拥有超能力?没错,就是那种可以自由操控、突破限制的超能力!...