# MobileSafe **Repository Path**: GDone/MobileSafe ## Basic Information - **Project Name**: MobileSafe - **Description**: android手机卫士 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-08-06 - **Last Updated**: 2020-12-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # MobileSafe -[可参考另一版本](https://github.com/huangguangda/DashuMobile) android手机卫士 ## Github 欢迎 Star、Fork ### 如果喜欢,那就点个赞吧!❤️ ## 手机安全卫士项目 ### 一,项目结构 下面我要讲解得很清楚,毅力这东西不是每个人都有的,天天学基础也不好,直接上手做项目也是可以的。MobileSafe这个该项目分为 9 个功能模块,包括手机防盗、通讯卫士、软件管家、手机杀毒、缓存清理、进程管理、流量统计、高级工具、设置中心。手机安全卫士,欢迎页面进入到主界面。 > 建议做这个项目之前,你是否学会Java基础语法,如果还没学,请先去系统学习一下,否则是看不下的。如果学过那就好,请开始你的项目历程。 下面开始从splash布局,获取版本名称并展示,在到构建服务端json和网络数据请求,json解析过程,消息机制发送不同类型的信息,弹出对话框,以及使用xutils的说明,打包apk可以自行了解,提示下载更新跳转到主界面。 首先先去下载Code tree for GitHub插件,它能帮助你更好地查看项目结构与分支下载功能。**图片资源也是用插件帮忙下载,如有不懂自行百度** 来源 Chrome 网上应用店 借用Code tree for GitHub插件功能找到libs下的jar包,下载下来导入项目中。 ``` xUtils-2.6.14.jar ``` xutils使用过程 1. 导入xutils的jar包 2. 添加xutils需要使用的权限 ``` ``` 3. 获取HttpUtils对象 4. 调用download(下载链接地址,下载后放置文件的路径,下载过程中方法的回调 ``` onStart() onloading() onSuccesd() onFail() ``` ## 包结构 ![包结构图](http://images.cnblogs.com/cnblogs_com/dashucoding/1247529/o_QQ%E6%88%AA%E5%9B%BE20180718225655.png) #### 创建activity_splash.xml ``` ``` > 说明:android:background="@drawable/launch_bg"为添加背景图片,android:shadowDx,android:shadowDy,android:shadowColor,android:shadowRadius为设置阴影效果。 #### 创建SplashActivity类 先进行初始化控件,显示版本号: ``` public class SplashActivity extends Activity { private TextView tv_version_name; private int mLocalVersionCode; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除掉当前activity头title,请求窗口。。自动提示导入,Window. no title,没有头部 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_splash); //初始化UI,这里定义一个方法 initUI(); //初始化数据,这里定义一个方法 initData(); } //...加入方法,显示红色自动导入 private void initUI(){ } //...加入方法,显示红色自动导入 private void initData(){ //中有getVersionCode()获取版本名称的方法 } //分开说明:说明@1 } ``` #### 说明@1 ``` /* * 初始化UI方法 * */ private void initUI() { tv_version_name = findViewById(R.id.tv_version_name); } ``` ``` /* * 获取数据方法 * */ private void initData() { //1.显示应用版本名称 getVersionName()为定义获得版本名称的方法。 tv_version_name.setText(getVersionName()); } ``` ``` /* * 获取版本名称:清单文件中 * @return 应用版本名称 放回null代表异常 * */ public String getVersionName(){ //版本名称为字符串,所以返回字符串对象 //1.获取包管理者,创建包管理者对象packageManager PackageManager pm = getPackageManager(); //2.包管理者获取包信息,从包管理者对象中,获取指定的包名 0代表获取基本信息 try { PackageInfo packageInfo = pm.getPackageInfo(this.getPackageName(), 0); //3.返回包信息的版本名称,获取版本名称 return packageInfo.versionName; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } //否则返回null,空字符串 return null; } ``` > 说明什么是版本名称?minSdkVersion,targetSdkVersion,versionCode,versionName是什么? - minSdkVersion指明应用程序运行所需的最小API level。 - targetSdkVersion标明应用程序目标API Level的一个整数。 - versionCode主要是用于版本升级所用,第一个版本定义为1,以后递增,这样只要判断该值就能确定是否需要升级,该值不显示给用户。 - android:versionName:这个是我们常说明的版本号,该值是个字符串,可以显示给用户。 ``` versionCode 1 versionName "1.0" // 那么1.0和1.0.0有何区别 在软件修改中,第三位代表修复了一些小bug而已,第二位代表修复了部分功能,第一位代表软件代码彻底大改动,几乎所有功能以及布局大变。 ``` #### 到了这里,就可以获取版本名称并且展示了。 ## 版本更新流程 启动app,从服务器获取最新的版本信息,检验是否有更新,弹出升级对话框,用户选择是否更新,下载安装包,安装apk,如果没有更新则跳转主界面,取消下载更新也同样跳转到主界面。 是否更新,获取当前versionCode与服务器的versionCode进行比较,如果服务器的大,那么有更新。 那么就在获取数据方法那添加代码吧! ``` /* * 获取数据方法 * */ //步骤:获取本地的版本号,与服务器的版本号进行比较。什么是服务器,可以理解为相当于一台电脑。 //分别获取本地版本号和服务器版本号 private void initData() { tv_version_name.setText(getVersionName()); //检测(本地版本号和服务器版本号对比)是否有更新,如果有更新,提示用户下载 //2.member(成员变量) mLocalVersionCode mLocalVersionCode = getVersionCode(); //3.获取服务器的版本号(客户端发送请求,服务端给响应(json,xml)) //http://www.xxx.com/update.json?key=value 返回200请求成功,流的方式将数据读取下来 //json中内容包含: /* * 更新版本的版本名称 * 新版本的描述信息 * 服务器版本号 * 新版本apk下载地址 * { * versionName:"2.0", * versionDes:"2.0版本发布了,狂拽炫酷吊炸天,快来下载啊", * versionCode:"2", * downloadUrl:"http://www.xxx.com/xxx.apk" * } * */ //获取服务端的数据,是要发请求,发请求是个耗时的操作,丢到子线程去 //检测版本号的方法 checkVersion(); } ``` > 这里是要服务器支持的,你可以下载tomcat在本地自己试试看。 ``` /* * 检测版本号 * */ private void checkVersion() { new Thread(){ public void run(){ //发送请求获取数据,参数则为请求json的链接地址 //http://ipconfig/update.json 测试阶段不是最优 //仅限于模拟器访问电脑tomcat //... Message.obtain()为将msg返还---public void handleMessage(Message msg) {} Message msg = Message.obtain(); //... long startTime = System.currentTimeMillis(); try { //1.封装url地址 URL url = new URL("http://ipconfig/update.json"); //2.开启一个链接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //3.设置常见请求参数(请求头) //请求超时 连接超时时间 跟服务器连接 connection.setConnectTimeout(2000); //读取超时 读取时候突然断了 connection.setReadTimeout(2000); //默认就是get请求方式 /*connection.setRequestMethod("POST");*/ //4.获取成功响应码 if (connection.getResponseCode() == 200){ //5.以流的形式,将数据获取下来 InputStream is=connection.getInputStream(); //6.将流转换字符串(工具类封装)--->----@2 这里另外创建一个工具类为StreamUtil,下面有描述 String json = StreamUtil.streamToString(is); Log.i(tag,json); //7.json解析 //创建JSON对象, new JSONObject JSONObject jsonObject = new JSONObject(json); String versionName = jsonObject.getString("versionName"); mVersionDes = jsonObject.getString("versionDes"); String versionCode = jsonObject.getString("versionCode"); mDownloadUrl = jsonObject.getString("downloadUrl"); //debug Log.i(tag,versionName); Log.i(tag, mVersionDes); Log.i(tag,versionCode); Log.i(tag, mDownloadUrl); //8.比对版本号(服务器的版本号>本地版本号,提示用户更新) //Integer.parseInt是因为上面的是字符串类型,所有要进行转换 if (mLocalVersionCode() { @Override public void onSuccess(ResponseInfo responseInfo) { //下载成功 (下载过后的放置在sd卡中的apk) Log.i(tag,"下载成功"); //返回下载responseInfo结果,下面定义一个方法提示用户安装 File file = responseInfo.result; //提示用户安装 -- 参数 安装文件 installApk(file); } @Override public void onFailure(HttpException e, String s) { Log.i(tag,"下载失败"); //下载失败 } //刚刚开始下载方法 @Override public void onStart() { Log.i(tag,"刚刚开始下载"); super.onStart(); } //下载过程中的方法 /* * 下载apk总大小 * 当前的下载位置 * 是否正在下载 * */ @Override public void onLoading(long total, long current, boolean isUploading) { Log.i(tag,"下载过程中"); super.onLoading(total, current, isUploading); } }); } } ``` ``` //这部分看源码 /* * 要去安装apk,你要告诉我apk放在哪啦 * @param file 安装文件 * */ private void installApk(File file) { //系统应用界面,源码,安装apk入口 Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); /*//文件作为数据源 intent.setData(Uri.fromFile(file)); //设置安装的类型 intent.setType("application/vnd.android.package-archive");*/ intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive"); // startActivity(intent); //----@5 startActivityForResult(intent, 0); } ``` ``` //开启一个activity后,返回结果调用的方法 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { enterHome(); super.onActivityResult(requestCode, resultCode, data); } ``` ``` /* * 进入应用程序的主界面 * */ private void enterHome() { Intent intent = new Intent(this, HomeActivity.class); startActivity(intent); //在开启一个新的界面后,将导航界面关闭(导航界面只可见一次) finish(); } ``` #### SplashActivity ``` public class SplashActivity extends Activity { protected static final String tag = "SplashActivity"; /* * 更新新版本的状态码 * */ private static final int UPDATE_VERSION = 100; /* * 进入应用程序主界面的状态码 * */ private static final int ENTER_HOME = 101; /* * url地址出错的状态码 * */ private static final int URL_ERROR = 102; private static final int IO_ERROR = 103; private static final int JSON_ERROR = 104; private TextView tv_version_name; private int mLocalVersionCode; //成员变量 private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { //super.handleMessage(msg); switch (msg.what){ case UPDATE_VERSION: //弹出对话框,提示用户更新 showUpdateDialog(); break; case ENTER_HOME: //进入应用程序主界面,activity跳转过程 enterHome(); break; case URL_ERROR: //弹出对话框,提示用户更新 //Toast.makeText(context,text,duration).show(); //ToastUtil.show(getApplicationContext(),"url异常"); ToastUtil.show(SplashActivity.this,"url异常"); enterHome(); break; case IO_ERROR: //弹出对话框,提示用户更新 //Toast.makeText(context,text,duration).show(); ToastUtil.show(SplashActivity.this,"读取异常"); enterHome(); break; case JSON_ERROR: //弹出对话框,提示用户更新 ToastUtil.show(SplashActivity.this,"json异常"); enterHome(); break; } } }; private String mVersionDes; private String mDownloadUrl; /* * 弹出对话框,提升用户更新 * */ private void showUpdateDialog() { //对话框,是依赖于activity存在的 AlertDialog.Builder builder = new AlertDialog.Builder(this); //设置左上角图标 builder.setIcon(R.drawable.ic_launcher); builder.setTitle("版本更新"); //设置描述内容 builder.setMessage(mVersionDes); //api 积极按钮,立即更新 builder.setPositiveButton("立即更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //下载apk,apk链接地址,downloadUrl downloadApk(); } }); //api builder.setNegativeButton("稍后再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取消对话框,进入主界面 enterHome(); dialog.dismiss(); } }); //点击取消监听 builder.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { //即使用户点击取消,也需要让其进入应用程序主界面 enterHome(); dialog.dismiss(); } }); builder.show(); } private void downloadApk() { //apk下载链接地址,放置apk的所在路径 //1.判断sd卡是否可用,是否挂在上 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //2.获取sd路径 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+"mobilesafe.apk"; //3.发生请求,获取apk,并且放置到指定路径 HttpUtils httpUtils = new HttpUtils(); //4.发送请求,传递参数(下载地址,下载应用放置位置) httpUtils.download(mDownloadUrl, path, new RequestCallBack() { @Override public void onSuccess(ResponseInfo responseInfo) { //下载成功 (下载过后的放置在sd卡中的apk) Log.i(tag,"下载成功"); File file = responseInfo.result; //提示用户安装 installApk(file); } @Override public void onFailure(HttpException e, String s) { Log.i(tag,"下载失败"); //下载失败 } //刚刚开始下载方法 @Override public void onStart() { Log.i(tag,"刚刚开始下载"); super.onStart(); } //下载过程中的方法 /* * 下载apk总大小 * 当前的下载位置 * 是否正在下载 * */ @Override public void onLoading(long total, long current, boolean isUploading) { Log.i(tag,"下载过程中"); super.onLoading(total, current, isUploading); } }); } } /* * 要去安装apk,你要告诉我apk放在哪啦 * @param file 安装文件 * */ private void installApk(File file) { //系统应用界面,源码,安装apk入口 Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); /*//文件作为数据源 intent.setData(Uri.fromFile(file)); //设置安装的类型 intent.setType("application/vnd.android.package-archive");*/ intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive"); // startActivity(intent); startActivityForResult(intent, 0); } //开启一个activity后,返回结果调用的方法 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { enterHome(); super.onActivityResult(requestCode, resultCode, data); } /* * 进入应用程序的主界面 * */ private void enterHome() { Intent intent = new Intent(this, HomeActivity.class); startActivity(intent); //在开启一个新的界面后,将导航界面关闭(导航界面只可见一次) finish(); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除掉当前activity头title requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_splash); //初始化UI initUI(); //初始化数据 initData(); } /* * 获取数据方法 * */ private void initData() { //1.应用版本名称 tv_version_name.setText(getVersionName()); //检测(本地版本号和服务器版本号对比)是否有更新,如果有更新,提示用户下载 //2.member(成员变量),获取本地的版本号 mLocalVersionCode = getVersionCode(); //3.获取服务器的版本号(客户端发送请求,服务端给响应(json,xml)) //http://www.xxx.com/update.json?key=value 返回200请求成功,流的方式将数据读取下来 //json中内容包含: /* * 更新版本的版本名称 * 新版本的描述信息 * 服务器版本号 * 新版本apk下载地址 * { * versionName:"2.0", * versionDes:"2.0版本发布了,狂拽炫酷吊炸天,快来下载啊", * versionCode:"2", * downloadUrl:"http://www.xxx.com/xxx.apk" * } * */ /* * HiJson 2.1.2_jdk64 * * */ //获取服务端的数据,是要发请求,发请求是个耗时的操作,丢到子线程去 checkVersion(); } /* * 检测版本号 * */ private void checkVersion() { new Thread(){ public void run(){ //发送请求获取数据,参数则为请求json的链接地址 //http://ipconfig/update.json 测试阶段不是最优 //仅限于模拟器访问电脑tomcat //Message message = new Message(); Message msg = Message.obtain(); long startTime = System.currentTimeMillis(); try { //1.封装url地址 URL url = new URL("http://ipconfig/update.json"); //2.开启一个链接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); //3.设置常见请求参数(请求头) //请求超时 连接超时时间 跟服务器连接 connection.setConnectTimeout(2000); //读取超时 读取时候突然断了 connection.setReadTimeout(2000); //默认就是get请求方式 /*connection.setRequestMethod("POST");*/ //4.获取成功响应码 if (connection.getResponseCode() == 200){ //5.以流的形式,将数据获取下来 InputStream is=connection.getInputStream(); //6.将流转换字符串(工具类封装) String json = StreamUtil.streamToString(is); Log.i(tag,json); //7.json解析 JSONObject jsonObject = new JSONObject(json); String versionName = jsonObject.getString("versionName"); mVersionDes = jsonObject.getString("versionDes"); String versionCode = jsonObject.getString("versionCode"); mDownloadUrl = jsonObject.getString("downloadUrl"); //debug Log.i(tag,versionName); Log.i(tag, mVersionDes); Log.i(tag,versionCode); Log.i(tag, mDownloadUrl); //8.比对版本号(服务器的版本号>本地版本号,提示用户更新) if (mLocalVersionCode 到主界面 [跳转](http://images.cnblogs.com/cnblogs_com/dashucoding/1247529/o_QQ%E6%88%AA%E5%9B%BE20180718213335.png) 这个过程中会有显示json解析失败,主要是因为没有解决服务器问题,这方面可自行下载tomcat,在本地自己尝试一下,把自己的update.json放入到D:\apache-tomcat-xx\webapps\ROOT 该目录下,apk也是同样的道理,不过这方面没资料有点,希望有需要的朋友自行百度或Google查阅。