由于项目需要root安装软件,并且希望在合适的时候引导用户去开启root安装,故需要检测手机是否root。

最基本的判断如下,直接运行一个底层命令。(参考https://github.com/Trinea/android-common/blob/master/src/cn/trinea/android/common/util/ShellUtils.java)

也可参考csdn http://blog.csdn.net/fm9333/article/details/12752415

     /**
* check whether has root permission
*
* @return
*/
public static boolean checkRootPermission() {
return execCommand("echo root", true, false).result == 0;
} /**
* execute shell commands
*
* @param commands
* command array
* @param isRoot
* whether need to run with root
* @param isNeedResultMsg
* whether need result msg
* @return <ul>
* <li>if isNeedResultMsg is false, {@link CommandResult#successMsg}
* is null and {@link CommandResult#errorMsg} is null.</li>
* <li>if {@link CommandResult#result} is -1, there maybe some
* excepiton.</li>
* </ul>
*/
public static CommandResult execCommand(String[] commands, boolean isRoot,
boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
return new CommandResult(result, null, null);
} Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null; DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(
isRoot ? COMMAND_SU : COMMAND_SH);
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
} // donnot use os.writeBytes(commmand), avoid chinese charset
// error
os.write(command.getBytes());
os.writeBytes(COMMAND_LINE_END);
os.flush();
}
os.writeBytes(COMMAND_EXIT);
os.flush(); result = process.waitFor();
// get command result
if (isNeedResultMsg) {
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(
process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(
process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
} if (process != null) {
process.destroy();
}
}
return new CommandResult(result, successMsg == null ? null
: successMsg.toString(), errorMsg == null ? null
: errorMsg.toString());
} /**
* result of command,
* <ul>
* <li>{@link CommandResult#result} means result of command, 0 means normal,
* else means error, same to excute in linux shell</li>
* <li>{@link CommandResult#successMsg} means success message of command
* result</li>
* <li>{@link CommandResult#errorMsg} means error message of command result</li>
* </ul>
*
* @author Trinea 2013-5-16
*/
public static class CommandResult { /** result of command **/
public int result;
/** success message of command result **/
public String successMsg;
/** error message of command result **/
public String errorMsg; public CommandResult(int result) {
this.result = result;
} public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
} /**
* execute shell command, default return result msg
*
* @param command
* command
* @param isRoot
* whether need to run with root
* @return
* @see ShellUtils#execCommand(String[], boolean, boolean)
*/
public static CommandResult execCommand(String command, boolean isRoot) {
return execCommand(new String[] { command }, isRoot, true);
}

但是这会带来一个问题,每次判断是否root都会弹出一个root请求框。这是十分不友好的一种交互方式,而且,用户如果选择取消,有部分手机是判断为非root的。

这是方法一。交互不友好,而且有误判。

在这个情况下,为了不弹出确认框,考虑到一般root手机都会有一些的特殊文件夹,比如/system/bin/su,/system/xbin/su,里面存放有相关的权限控制文件。

因此只要手机中有一个文件夹存在就判断这个手机root了。

然后经过测试,这种方法在大部分手机都可行。

代码如下:

     /** 判断是否具有ROOT权限 ,此方法对有些手机无效,比如小米系列 */
public static boolean isRoot() { boolean res = false; try {
if ((!new File("/system/bin/su").exists())
&& (!new File("/system/xbin/su").exists())) {
res = false;
} else {
res = true;
}
;
} catch (Exception e) {
res = false;
}
return res;
}

这是方法二。交互友好,但是有误判。

后来测试的过程中发现部分国产,比如小米系列,有这个文件夹,但是系统是未root的,判断成了已root。经过分析,这是由于小米有自身的权限控制系统而导致。

考虑到小米手机有大量的用户群,这个问题必须解决,所以不得不寻找第三种方案。

从原理着手,小米手机无论是否root,应该都是具有相关文件的。但是无效的原因应该是,文件设置了相关的权限。导致用户组无法执行相关文件。

从这个角度看,就可以从判断文件的权限入手。

先看下linux的文件权限吧。

linux文件权限详细可参考《鸟叔的linux私房菜》http://vbird.dic.ksu.edu.tw/linux_basic/0210filepermission.php#filepermission_perm

只需要在第二种方法的基础上,再另外判断文件拥有者对这个文件是否具有可执行权限(第4个字符的状态),就基本可以确定手机是否root了。

在已root手机上(三星i9100 android 4.4),文件权限(x或者s,s权限,可参考http://blog.chinaunix.net/uid-20809581-id-3141879.html)如下

未root手机,大部分手机没有这两个文件夹,小米手机有这个文件夹。未root小米手机权限如下(由于手头暂时没有小米手机,过几天补上,或者有同学帮忙补上,那真是感激不尽)。

【等待补充图片】

代码如下:

     /** 判断手机是否root,不弹出root请求框<br/> */
public static boolean isRoot() {
String binPath = "/system/bin/su";
String xBinPath = "/system/xbin/su";
if (new File(binPath).exists() && isExecutable(binPath))
return true;
if (new File(xBinPath).exists() && isExecutable(xBinPath))
return true;
return false;
} private static boolean isExecutable(String filePath) {
Process p = null;
try {
p = Runtime.getRuntime().exec("ls -l " + filePath);
// 获取返回内容
BufferedReader in = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String str = in.readLine();
Log.i(TAG, str);
if (str != null && str.length() >= 4) {
char flag = str.charAt(3);
if (flag == 's' || flag == 'x')
return true;
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(p!=null){
p.destroy();
}
}
return false;
}

这种方法基本可以判断所有的手机,而且不弹出root请求框。这才是我们需要的,perfect。

方法三,交互友好,基本没有误判。

以下是apk以及相关源代码,大家可以下载apk看下运行效果

ROOT检测APK下载地址:http://good.gd/3091610.htm

ROOT检测代码下载:http://good.gd/3091609.htm或者http://download.csdn.net/detail/waylife/7639017

如果有手机使用方法三无法判断,欢迎提出。

也欢迎大家提出其他的更好的办法。

【Android】不弹root请求框检测手机是否root的更多相关文章

  1. android 透明弹出搜索框

    1.在QQ一些APP当中有是弹出一个半透明的搜索框的,其实这种效果就是很多种方法,自定义一个Dialog,或者直接将activity的背景变成半透明的也可以的. 下面就是将activity变成半透明的 ...

  2. Android手机一键Root原理分析

    图/文 非虫 一直以来,刷机与Root是Android手机爱好者最热衷的事情.即使国行手机的用户也不惜冒着失去保修的风险对Root手机乐此不疲.就在前天晚上,一年一度的Google I/O大会拉开了帷 ...

  3. android标题栏上面弹出提示框(二) PopupWindow实现,带动画效果

    需求:上次用TextView写了一个从标题栏下面弹出的提示框.android标题栏下面弹出提示框(一) TextView实现,带动画效果,  总在找事情做的产品经理又提出了奇葩的需求.之前在通知栏显示 ...

  4. android标题栏下面弹出提示框(一) TextView实现,带动画效果

    产品经理用的是ios手机,于是android就走上了模仿的道路.做这个东西也走了一些弯路,写一篇博客放在这里,以后自己也可用参考,也方便别人学习. 弯路: 1.刚开始本来用PopupWindow去实现 ...

  5. 禁止手机页面中A标签长按弹出路径框

    //禁止手机页面中A标签长按弹出路径框    window.onload=function(){        document.documentElement.style.webkitTouchCa ...

  6. Android弹出选项框及指示箭头动画选择

     Android弹出选项框及指示箭头动画选择 Android原生的Spinner提供了下拉列表选项框,但在一些流行的APP中,原生的Spinner似乎不太受待见,而通常会有下图所示的下拉列表选项框 ...

  7. Android Studio 打开弹出警告框

    1.Android Studio打开后,自己的项目没有打开,就弹出了警告框,重启之后依然弹出警告框: 警告框内容:"Cannot load project: java.lang.Illega ...

  8. Cocos2d-x C++调用Android弹出提示框

    转载请注明地址,谢谢.. Cocos2d-x中提供了一个JniHelper类来让我们对Jni进行操作. (PS:弄了一天想自己写代码操作Jni的,但是总是出错,技术差不得不使用Cocos2d-x现成的 ...

  9. Ajax发送请求等待时弹出模态框等待提示

    主要的代码分为两块,一个是CSS定义模态框,另一个是在Ajax中弹出模态框. 查看菜鸟教程中的模态框教程demo,http://www.runoob.com/try/try.php?filename= ...

随机推荐

  1. 国内银行CNAPS CODE 查询 苹果开发者,应用内购,需要填写税务相关信息必须的

    https://e.czbank.com/CORPORBANK/QYUK http://weekend.blog.163.com/blog/static/746895820127961346724/

  2. JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-006类型转换器( @Converter(autoApply = true) 、type="converter:qualified.ConverterName" )

    一.结构 二.代码 1. package org.jpwh.model.advanced; import java.io.Serializable; import java.math.BigDecim ...

  3. [iOS]ARC和MRC下混编

    1.在MRC工程中使用ARC的文件(例如AFNetworking,SDWebImage,MJRefresh等)在Build Phases里找到对应.m 在后面添加-fobjc-arc(代表这个文件使用 ...

  4. TCP释放连接的四次挥手过程

    TCP断开连接的过程:TCP四次挥手. 数据传输结束后,通信的双方都可释放连接.现在A和B都处于ESTABLISHED状态.A的应用进程先向TCP发出连接释放报文段,主动关闭TCP连接.A把连接释放报 ...

  5. Largest Rectangle in Histogram-最大长方形

    题目描述: 给定n个非负整数height[n],分别代表直方图条的高,每个条的宽设为1,求直方图中面积最大的矩形的面积 题目来源: http://oj.leetcode.com/problems/la ...

  6. 5、java反射基础

    Class对象: Class对象记录了所有与类相关的信息,当类加载器从文件系统中加载.class文件到JVM中的同时会为每一个类创建一个Class对象.通过Class对象可以获取到类的属性.方法.构造 ...

  7. z-index无效问题的解决方法

    在使用z-index这个属性之前,我们必须先了解使用z-index的必要条件: 1.要想给元素设置z-index样式,必须先让它变成定位元素,说的明白一点,就是要给元素设置一个postion:rela ...

  8. 【分享】Maven插件的源码下载(SVN)

    偶然的情况下找到了Maven插件源码的网址,现分享下 http://svn.apache.org/repos/asf/maven/plugins/ 可以使用SVN下载,在添加新的资源路径时,把上面的网 ...

  9. R语言记录程序运行的时间

    f <- function(start_time) { start_time <- as.POSIXct(start_time) dt <- difftime(Sys.time(), ...

  10. Java中的private、protected、public和default的区别

        (1)对于public修饰符,它具有最大的访问权限,可以访问任何一个在CLASSPATH下的类.接口.异常等.它往往用于对外的情况,也就是对象或类对外的一种接口的形式. (2)对于protec ...