您好,登錄后才能下訂單哦!
根據(jù)功能模塊劃分(Android開發(fā)推薦此方法)
- Activity mobilesafe.activty
- 后臺(tái)服務(wù) mobilesafe.service
- 廣播接受者 mobilesafe.receiver
- 數(shù)據(jù)庫 mobilesafe.db.dao
- 對(duì)象(java bean) mobilesafe.domain/bean
- 自定義控件 mobilesafe.view
- 工具類 mobilesafe.utils
- 業(yè)務(wù)邏輯 mobilesafe.engine
閃屏頁面(Splash)作用:
- 展示logo,公司品牌
- 項(xiàng)目初始化
- 檢測(cè)版本更新
- 校驗(yàn)程序合法性(比如:判斷是否有網(wǎng)絡(luò),有的話才運(yùn)行)
AndroidMinifest.xml 四大組件都需要在這里配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.mxn.mobilesafe" android:versionCode="1" //版本號(hào) android:versionName="1.0" > //版本名 <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="21" /> //項(xiàng)目所需的權(quán)限 <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/> <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"/> <uses-permission android:name="android.permission.CLEAR_APP_CACHE"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > //主題 //activity的注冊(cè) <activity android:name="com.mxn.mobilesafe.activity.SplashActivity" android:label="@string/app_name" > <intent-filter> //起始的activity <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.mxn.mobilesafe.activity.HomeActivity" /> <activity android:name="com.mxn.mobilesafe.activity.SettingActivity" /> <activity android:name="com.mxn.mobilesafe.activity.LostFindActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.Setup1Activity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.Setup2Activity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.Setup3Activity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.Setup4Activity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.ContactActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.AtoolsActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.AddressActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.CallSafeActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.AppManagerActivity" > </activity> <activity android:name="com.mxn.mobilesafe.activity.TaskManagerActivity"> </activity> <activity android:name="com.mxn.mobilesafe.activity.TaskManagerSettingActivity"> </activity> <activity android:name="com.mxn.mobilesafe.activity.AntivirusActivity"></activity> <activity android:name="com.mxn.mobilesafe.activity.AppLockActivity"></activity> <activity android:name="com.mxn.mobilesafe.activity.CleanCacheActivity"></activity> //廣播接收者的 注冊(cè) <receiver android:name=".receiver.BootCompleteReceiver" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <receiver android:name=".receiver.SmsReceiver" > <intent-filter android:priority="2147483647" > <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> <!-- <receiver android:name=".receiver.OutCallReceiver" >靜態(tài)注冊(cè)的廣播 <intent-filter> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver> --> //服務(wù)的注冊(cè) <service android:name="com.mxn.mobilesafe.service.LocationService" > </service> <service android:name="com.mxn.mobilesafe.service.AddressService" > </service> <service android:name="com.mxn.mobilesafe.service.KillProcessService"></service> <service android:name="com.mxn.mobilesafe.service.WatchDogService"></service> </application> </manifest>
activity_splash.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.mxn.mobilesafe.SplashActivity" android:background="@drawable/launcher_bg" android:id="@+id/rl_root"> <TextView android:id="@+id/tv_version" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="202dp" android:textSize="22sp" android:textColor="#000" android:shadowColor="#f00" //對(duì)版本號(hào)設(shè)置陰影 android:shadowDx="1" android:shadowDy="1" android:shadowRadius="1" android:text="版本號(hào):1.0" /> <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/tv_version" android:layout_centerHorizontal="true" android:layout_marginTop="54dp" /> <TextView android:id="@+id/tv_progress" android:visibility="gone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:textColor="#f00" android:textSize="16sp" android:text="下載進(jìn)度" /> </RelativeLayout>
SplashActivity.java
public class SplashActivity extends Activity { protected static final int CODE_UPDATE_DIALOG; protected static final int CODE_URL_ERROR; protected static final int CODE_NET_ERROR; protected static final int CODE_JSON_ERROR; protected static final int CODE_ENTER_HOME; private TextView tvVersion; private TextView tvProgress;// 下載進(jìn)度展示 // 服務(wù)器返回的信息 private String mversionName;// 版本名 private int mversionCode;// 版本號(hào) private String mDesc;// 版本描述 private String mdowmloadurl;// 下載地址 private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { case CODE_UPDATE_DIALOG: showUpdateDialog();//顯示升級(jí)對(duì)話框 break; case CODE_URL_ERROR: Toast.makeText(SplashActivity.this, "url錯(cuò)誤", Toast.LENGTH_SHORT).show(); enterHome(); break; case CODE_NET_ERROR: Toast.makeText(SplashActivity.this, "網(wǎng)絡(luò)錯(cuò)誤", Toast.LENGTH_SHORT).show(); enterHome(); break; case CODE_JSON_ERROR: Toast.makeText(SplashActivity.this, "json數(shù)據(jù)解析解析錯(cuò)誤", Toast.LENGTH_SHORT).show(); enterHome(); break; case CODE_ENTER_HOME: enterHome(); break; default: break; } }; }; private SharedPreferences sp; private RelativeLayout rlRoot; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); tvVersion = (TextView) findViewById(R.id.tv_version); tvProgress = (TextView) findViewById(R.id.tv_progress);// 默認(rèn)隱藏 tvVersion.setText("版本號(hào):" + getVersionCode());//給版本號(hào)設(shè)置內(nèi)容,動(dòng)態(tài)獲取的值 rlRoot = (RelativeLayout) findViewById(R.id.rl_root); //判斷是否需要自動(dòng)更新 sp = getSharedPreferences("config", MODE_PRIVATE); boolean autoUpdate = sp.getBoolean("auto_update", true); copyDB("address.db");//拷貝歸屬地查詢數(shù)據(jù)庫 copyDB("antivirus.db");//拷貝病毒庫 //更新病毒庫 updateVirus(); if(autoUpdate){ checkVersion(); }else{ mHandler.sendEmptyMessageDelayed(CODE_ENTER_HOME, 2000); } //閃屏頁漸變動(dòng)畫效果 AlphaAnimation anim = new AlphaAnimation(0.3f, 1f); anim.setDuration(2000); rlRoot.startAnimation(anim); } //更新病毒數(shù)據(jù)庫 private void updateVirus() { //聯(lián)網(wǎng)從服務(wù)器獲取到最近數(shù)據(jù)的MD5的特征碼 HttpUtils httputils = new HttpUtils(); String url = "http://172.28.3.112:8080/virus.json"; httputils.send(HttpMethod.GET, url, new RequestCallBack<String>(){ @Override public void onFailure(HttpException arg0, String arg1) { // TODO Auto-generated method stub } @Override public void onSuccess(ResponseInfo<String> arg0) { // TODO Auto-generated method stub //System.out.println(arg0.result); // JSONObject jsonobject = new JSONObject(arg0.result); // String md5 = jsonobject.getString("md5"); // String desc = jsonobject.getString("desc"); } }); } // 獲取本地版本號(hào) private int getVersionCode() { PackageManager packgeManager = getPackageManager();//拿到包的管理者。。包管理器,獲取手機(jī)里面每個(gè)apk的信息(清單文件信息) try {// 獲取包的信息。。 getPackageName()當(dāng)前應(yīng)用程序的包名 等于 package="com.mxn.mobilesafe" PackageInfo packageInfo = packgeManager.getPackageInfo(getPackageName(), 0); int versionCode = packageInfo.versionCode; String versionName = packageInfo.versionName; System.out.println("versionname=" + versionName + ";" + "versioncode=" + versionCode); return versionCode; } catch (NameNotFoundException e) { // 沒有找到包名時(shí) e.printStackTrace(); } return -1; } // 從服務(wù)器獲取版本信息進(jìn)行校驗(yàn) private void checkVersion() { final long startTime = System.currentTimeMillis(); new Thread() {// 網(wǎng)絡(luò)訪問在分線程異步加載數(shù)據(jù) public void run() { Message msg = Message.obtain(); HttpURLConnection con = null; try {// 本機(jī)地址:localhost 如果用模擬器加載本機(jī)的地址:用10.0.0.2來替換 URL url = new URL("http://10.0.2.2:8080/update.json"); // 打開連接 con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");//設(shè)置請(qǐng)求方法 con.setConnectTimeout(5000);// 設(shè)置連接超時(shí),5S con.setReadTimeout(5000);// 設(shè)置響應(yīng)超時(shí),鏈接上了,但服務(wù)器遲遲沒有響應(yīng) con.connect();// 鏈接服務(wù)器 int responseCode = con.getResponseCode();//獲取響應(yīng)碼 if (responseCode == 200) { // 獲取返回值 InputStream inputStream = con.getInputStream(); // 流轉(zhuǎn)化為字符串 String result = StreamUtils.readFormStream(inputStream);//自己定義的StreamUtils工具類 System.out.println("網(wǎng)絡(luò)結(jié)果返回:" + result); //result是一個(gè)json字符串,進(jìn)行解析 // 解析json JSONObject jo = new JSONObject(result); mversionName = jo.getString("versionName");//拿到服務(wù)器端的版本名 mversionCode = jo.getInt("versionCode");//拿到服務(wù)器端的版本號(hào) mDesc = jo.getString("description");//拿到服務(wù)器端的版本描述 mdowmloadurl = jo.getString("downloadUrl");//拿到服務(wù)器端的下載鏈接 System.out.println(mDesc); System.out.println(mversionCode); // 服務(wù)器的大于 本地的,判斷是否有更新,如果大于 則有更新需要更新,彈出升級(jí)對(duì)話框 if (mversionCode > getVersionCode()) { System.out.println("進(jìn)行比較,有版本更新"); msg.what = CODE_UPDATE_DIALOG; // showUpdateDialog();//這句是在子線程更新界面,android不能在子線程更新界面,要想在子線程更新界面所以用到handler. } else {// 如果沒有版本更新 msg.what = CODE_ENTER_HOME; } } } catch (MalformedURLException e) {// url錯(cuò)誤的異常 msg.what = CODE_URL_ERROR; e.printStackTrace(); } catch (IOException e) {//網(wǎng)絡(luò)錯(cuò)誤異常 // 這個(gè)是可以攜帶數(shù)據(jù)的msg.obj = msg.what = CODE_NET_ERROR;// what只是一個(gè)標(biāo)識(shí),用來區(qū)分消息! e.printStackTrace(); } catch (JSONException e) {// json解析失敗 msg.what = CODE_JSON_ERROR; e.printStackTrace(); } finally { long endTime = System.currentTimeMillis(); long timeUsed = endTime - startTime;// 訪問網(wǎng)絡(luò)花費(fèi)的時(shí)間 if (timeUsed < 2000) { try {// 強(qiáng)制休眠2s,保證閃屏頁面2S Thread.sleep(2000 - timeUsed); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } mHandler.sendMessage(msg);// 消息發(fā)送出去,在handlemessage里進(jìn)行相應(yīng)的處理 if (con != null) { con.disconnect(); } } } }.start(); } //升級(jí)對(duì)話框 private void showUpdateDialog() { System.out.println("正在升級(jí)對(duì)話框"); // 升級(jí)對(duì)話框 AlertDialog.Builder builder = new AlertDialog.Builder(this);//context對(duì)象 builder.setTitle("最新版本" + mversionName); builder.setMessage(mDesc); // builder.setCancelable(false);//不讓用戶取消對(duì)話框,用戶體驗(yàn)太差 builder.setPositiveButton("立即更新", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub System.out.println("立即更新"); // download方法 download(); } }); builder.setNegativeButton("以后再說", new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { enterHome(); } }); builder.setOnCancelListener(new OnCancelListener() { // 設(shè)置取消監(jiān)聽,用戶點(diǎn)擊返回鍵時(shí)觸發(fā) @Override public void onCancel(DialogInterface dialog) { enterHome(); } }); builder.show(); } protected void download() {// 下載服務(wù)器端的apk文件 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { // 判斷是否有sd卡,sd卡掛載的時(shí)候才可以 tvProgress.setVisibility(View.VISIBLE);// 顯示進(jìn)度 String target = Environment.getExternalStorageDirectory() + "/update.apk";//把文件下載到哪個(gè)路徑下,sd卡的根目錄 // xutils框架,使用HttpUtils工具下載文件,下載一個(gè)jar包 HttpUtils utils = new HttpUtils(); utils.download(mdowmloadurl, target, new RequestCallBack<File>() { @Override // 文件下載進(jìn)度 public void onLoading(long total, long current, boolean isUploading) { // TODO Auto-generated method stub super.onLoading(total, current, isUploading); System.out.println("下載進(jìn)度:" + current + "/" + total); tvProgress.setText("下載進(jìn)度:" + current * 100 / total + "%"); } @Override public void onSuccess(ResponseInfo<File> arg0) { // TODO Auto-generated method stub Toast.makeText(SplashActivity.this, "下載成功", Toast.LENGTH_SHORT).show(); // 下載完成之后,跳到系統(tǒng)的安裝界面。。Intent.ACTION_VIEW 是xml的action 標(biāo)簽 Intent intent = new Intent(Intent.ACTION_VIEW);//系統(tǒng)的安裝界面 intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setDataAndType(Uri.fromFile(arg0.result), "application/vnd.android.package-archive"); // startActivity(intent); startActivityForResult(intent, 0);// 如果用戶取消安裝,會(huì)返回結(jié)果,回調(diào)方法onActivityResult,下文定義 } @Override public void onFailure(HttpException arg0, String arg1) { // TODO Auto-generated method stub Toast.makeText(SplashActivity.this, "下載失敗", Toast.LENGTH_SHORT).show(); } }); } else { Toast.makeText(SplashActivity.this, "沒有SD卡", Toast.LENGTH_SHORT).show(); } } @Override//用戶取消安裝,回調(diào)此方法 protected void onActivityResult(int requestCode, int resultCode, Intent data) { // TODO Auto-generated method stub System.out.println("出現(xiàn)安裝界面,用戶點(diǎn)擊取消時(shí)。"); enterHome(); super.onActivityResult(requestCode, resultCode, data); } private void enterHome() {// 進(jìn)入主界面 Intent intent = new Intent(this, HomeActivity.class); startActivity(intent); finish(); } //拷貝數(shù)據(jù)庫,從assets目錄下拷貝到data/data/com.mxn.mobilesafe/files目錄下 private void copyDB(String dbName){ //獲取文件路徑 File destFile = new File(getFilesDir(),dbName); if(destFile.exists()){ System.out.println("已存在"); } FileOutputStream out = null; InputStream in = null; try { in = getAssets().open(dbName); out = new FileOutputStream(destFile); int len = 0; byte[] buffer = new byte[1024]; while((len = in.read(buffer))!=-1){ out.write(buffer,0,len); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { in.close(); out.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
StreamUtils.java
/* * 讀取流的工具 * 把流對(duì)象轉(zhuǎn)換成字符串對(duì)象 */ public class StreamUtils { //將輸入流讀取成String后返回 public static String readFormStream(InputStream in) throws IOException{ // 定義字節(jié)數(shù)組輸出流對(duì)象 ByteArrayOutputStream out = new ByteArrayOutputStream(); // 定義讀取的長(zhǎng)度 int len = 0 ; // 定義讀取的緩沖區(qū) byte[] buffer = new byte[1024]; // 按照定義的緩沖區(qū)進(jìn)行循環(huán)讀取,直到讀取完畢為止 while((len=in.read(buffer))!=-1){ // 根據(jù)讀取的長(zhǎng)度寫入到字節(jié)數(shù)組輸出流對(duì)象中 out.write(buffer,0,len); } String result = out.toString(); // 關(guān)閉流 in.close(); out.close(); return result; // // 把讀取的字節(jié)數(shù)組輸出流對(duì)象轉(zhuǎn)換成字節(jié)數(shù)組 // byte data[] = out.toByteArray(); // // 按照指定的編碼進(jìn)行轉(zhuǎn)換成字符串(此編碼要與服務(wù)端的編碼一致就不會(huì)出現(xiàn)亂碼問題了,android默認(rèn)的編碼為UTF-8) // return new String(data, "UTF-8"); } }
系統(tǒng)安裝界面的activity的配置:
<activity android:name=".PackageInstallerActivity" android:configChanges="orientation|keyboardHidden" android:theme="@style/Theme.Transparent"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="content" /> <data android:scheme="file" /> <data android:mimeType="application/vnd.android.package-archive" /> </intent-filter> </activity>
我們服務(wù)器用的是tomcat,里面放置 新版本的apk和update.json:
將代碼打包為apk文件:
涉及的知識(shí)點(diǎn):
PackageManager 包管理器,獲取手機(jī)里面每個(gè)apk的信息(清單文件信息)
版本更新流程:
網(wǎng)絡(luò)請(qǐng)求
> * URL
> * HttpUrlConntetion
JSON解析
> * JSONObject 專門用來解析json
> * JSONArray
對(duì)話框彈出
> AlertDialog
> AlertDialog.Builder
子線程更新UI
> * Handler + message
> * runOnUiThread(runnable)
頁面之間的跳轉(zhuǎn)Intent
GitHub 一個(gè)開源的網(wǎng)站,下載xUtils框架,將下載的jar包導(dǎo)入工程。
AlertDialog.Builder(this)
子類擁有父類的所有方法, 而且可以有更多自己的方法。父類無法有子類的方法
Activity(token), Context(沒有token)
平時(shí),要獲取context對(duì)象的話, 優(yōu)先選擇Activity, 避免bug出現(xiàn), 盡量不用getApplicationContext()
activity是context的子類
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,同時(shí)也希望多多支持億速云!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。