Android 자동 업데이트 실현

15784 단어
Android 자동 업데이트 실현
필요:
우리 가 앱 을 개발 하 는 과정 에서 이런 수요 에 부 딪 힐 수 있다.앱 이 실 행 될 때 새 버 전이 나 왔 는 지 확인 하고 업데이트 합 니 다.앱 의 내부 자동 업 데 이 트 를 어떻게 실현 하 는 지 오늘 소개 한다.
인터페이스 가 져 오기
우선, 우 리 는 백 엔 드 에서 버 전 정보 데 이 터 를 얻 고 백 엔 드 에서 제공 하 는 인 터 페 이 스 를 통 해 데 이 터 를 되 돌려 야 합 니 다.데이터 형식 은 JSon 을 사용 합 니 다. 예제 텍스트 는 다음 과 같 습 니 다.
{
    "appname":"Will.apk",
    "serverVersion":"1.0.2",
    "serverFlag":"1",
    "lastForce":"1",
    "updateurl":"http://www.baidu.com",
    "upgrateinfo":"V1.0.2    ,      !"
}

학습 과정 에서 백 엔 드 가 인 터 페 이 스 를 제공 하지 않 는 다 면 제 다른 글 을 참고 하여 Jhipster 를 사용 하여 간단 한 API 인 터 페 이 스 를 만 듭 니 다.Jhipster 단순 사용
실현 과정
다음은 우리 안 드 로 이 드 엔 드 의 실현 을 시작 하 겠 습 니 다.사고방식: 1. 백 엔 드 인 터 페 이 스 를 연결 하 는 데 사용 되 는 bean 의 업 데 이 트 를 실현 합 니 다. 2. retrofit 를 사용 하여 버 전의 업 데 이 트 를 요청 하 는 인터페이스 3. APK 다운로드 4. BroadcastReceiver 를 통 해 다운로드 완료 여 부 를 감청 합 니 다.
STEP 1: JSon 데 이 터 를 받 아들 이 는 클래스 만 들 기
인터페이스 에서 얻 은 JSon 데 이 터 는 다음 과 같은 클래스 로 분석 해 야 합 니 다.
public class UpdateAppInfo {

    private String appname;
    private String serverVersion;
    private String serverFlag;
    private String lastForce;
    private String updateurl;
    private String upgradeinfo;

    public String getAppname() {
        return appname;
    }

    public void setAppname(String appname) {
        this.appname = appname;
    }

    public String getServerVersion() {
        return serverVersion;
    }

    public void setServerVersion(String serverVersion) {
        this.serverVersion = serverVersion;
    }

    public String getServerFlag() {
        return serverFlag;
    }

    public void setServerFlag(String serverFlag) {
        this.serverFlag = serverFlag;
    }

    public String getLastForce() {
        return lastForce;
    }

    public void setLastForce(String lastForce) {
        this.lastForce = lastForce;
    }

    public String getUpdateurl() {
        return updateurl;
    }

    public void setUpdateurl(String updateurl) {
        this.updateurl = updateurl;
    }

    public String getUpgradeinfo() {
        return upgradeinfo;
    }

    public void setUpgradeinfo(String upgradeinfo) {
        this.upgradeinfo = upgradeinfo;
    }

    @Override
    public String toString() {
        return "UpdateAppInfo{" +
            "appname='" + appname + '\'' +
            ", serverVersion='" + serverVersion + '\'' +
            ", serverFlag='" + serverFlag + '\'' +
            ", lastForce='" + lastForce + '\'' +
            ", updateurl='" + updateurl + '\'' +
            ", upgradeinfo='" + upgradeinfo + '\'' +
            '}';
    }
}

STEP 2: Retrofit + RxJava 네트워크 인터페이스 구현
먼저 가입 의존:
/ / Android 지원 Rxjava / / 여 기 는 RxJava 2 버 전 compile 'io. reactivex. rxjava 2: rxjava: 2.0.1' compile 'io. reactivex. rxjava 2: rxandroid: 2.0.1' / Android 지원 Retrofit compile 'com. squareup. retrofit 2: retrofit: 2.1.0' / 연결 Retrofit & RxJava 2 / 여 기 는 RxJava 2 버 전 compile 'com. jakewharton. retrofit: retrofit2-rxjava2-adapter:1.0.0'
다음 네트워크 인터페이스 만 들 기:
public interface NetService{
    @GET("/api/update-infos/1")
    Observable getUpdateInfo();
}

공장 모드 를 통 해 NetService 를 만 듭 니 다.
public class ServiceFactory{
    private static final String BaseUrl = "http://10.10.2.87:8080"
    public static  T createServiceFrom(final Class serviceClass){
        Retrofit adapter = new Retrofit.Builder()
            .baseUrl(BaseUrl)
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) //   Rx   
                .addConverterFactory(GsonConverterFactory.create()) //   Gson   
                .build();
        return adapter.create(serviceClass);
    }
}

단계 3: 검 측 버 전 업데이트 인터페이스 만 들 기
public class CheckUpdateUtils {

    @SuppressWarnings("unused")
    public static void checkUpdate(String appCode,String curVersion,final CheckCallBack updateCallback){
        ApiService apiService = ServiceFactory.createServiceFrom(ApiService.class);
        Log.e("check","       1");
        String appName = "hoolay";
        apiService.getCall()
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subject() {
                    @Override
                    public boolean hasObservers() {
                        return false;
                    }

                    @Override
                    public boolean hasThrowable() {
                        return false;
                    }

                    @Override
                    public boolean hasComplete() {
                        return false;
                    }

                    @Override
                    public Throwable getThrowable() {
                        return null;
                    }

                    @Override
                    protected void subscribeActual(Observer super UpdateAppInfo> observer) {

                    }

                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(UpdateAppInfo value) {
                        if(value.equals(null)||value.getUpdateurl().equals(null)){
                            Log.e("check","       2");
                            updateCallback.onError();
                        }else {
                            Log.e("check","       3");
                            updateCallback.onSuccess(value);
                        }
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }
}


여기 에는 결과 리 셋 감청 이 필요 하 다.
//            
public interface CheckAllBack{
    void onSuccess(UpdateAppInfo updateInfo);
    void onError();
}

STEP 4: 액 티 비 티 에서 완 성 된 부분
  • 현재 버 전 번호 와 버 전 이름 을 가 져 오 는 클래스 만 들 기
  • /**
     *                  
     */
    
    public class ApkVersionCodeUtils {
        /**
         *       apk   
         *
         * @param mContext
         * @return
         */
        public static int getVersionCode(Context mContext) {
            int versionCode = 0;
            try {
                //       ,  AndroidManifest.xml android:versionCode
                versionCode = mContext.getPackageManager().
                        getPackageInfo(mContext.getPackageName(), 0).versionCode;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return versionCode;
        }
    
        /**
         *        
         *
         * @param context    
         * @return
         */
        public static String getVerName(Context context) {
            String verName = "";
            try {
                verName = context.getPackageManager().
                        getPackageInfo(context.getPackageName(), 0).versionName;
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
            return verName;
        }
    }
    
  • 네트워크 연결 을 통 해 업데이트 가 필요 한 지 확인
  • CheckUpdateUtils.checkUpdate("apk", "1.0.0", new CheckCallBack() {
                @Override
                public void onSuccess(UpdateAppInfo updateAppInfo) {
                    String isForce = updateAppInfo.getLastForce();
                    String downUrl = updateAppInfo.getUpdateurl();
                    String updateinfo = updateAppInfo.getUpgradeinfo();
                    String appName = updateAppInfo.getAppname();
                    Log.e("aaa",appName);
                    if(isForce.equals("1")&& !TextUtils.isEmpty(updateinfo)){//    
                        forceUpdate(MainActivity.this,appName,downUrl,updateinfo);
                    }else{//     
                        //    
                        normalUpdate(MainActivity.this,appName,downUrl,updateinfo);
                    }
                }
    
                @Override
                public void onError() {
                    noneUpdate(MainActivity.this);
                }
            });
    
  • 업데이트 대화 상자 사용:
  • private void forceUpdate(final Context context, final String appName, final String downUrl, final String updateinfo) {
            mDialog = new AlertDialog.Builder(context);
            mDialog.setTitle(appName+"    !");
            mDialog.setMessage(updateinfo);
            mDialog.setPositiveButton("    ", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    if (!canDownloadState()) {
                        showDownloadSetting();
                        return;
                    }
                    //      DownLoadApk.download(MainActivity.this,downUrl,updateinfo,appName);
         AppInnerDownLoder.downLoadApk(MainActivity.this,downUrl,appName);
                }
            }).setCancelable(false).create().show();
        }
    

    STEP 5: HttpUrlConnection 으로 다운로드
    public class AppInnerDownLoder {
        public final static String SD_FOLDER = Environment.getExternalStorageDirectory()+ "/VersionChecker/";
        private static final String TAG = AppInnerDownLoder.class.getSimpleName();
    
        /**
         *        APK
         */
        @SuppressWarnings("unused")
        public static void downLoadApk(final Context mContext,final String downURL,final String appName ) {
    
            final ProgressDialog pd; //       
            pd = new ProgressDialog(mContext);
            pd.setCancelable(false);//        ,    
            pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            pd.setMessage("       ,   ");
            pd.setTitle("    ");
            pd.show();
            new Thread() {
                @Override
                public void run() {
                    try {
                        File file = downloadFile(downURL,appName, pd);
                        sleep(3000);
                        installApk(mContext, file);
                        //          
                        pd.dismiss();
                    } catch (Exception e) {
                        pd.dismiss();
    
                    }
                }
            }.start();
        }
    
        /**
         *             
         * 
         * @param path
         *                
         * @param pd
         *               
         * @return
         * @throws Exception
         */
        private static File downloadFile(String path,String appName ,ProgressDialog pd) throws Exception {
            //            sdcard            
            if (Environment.MEDIA_MOUNTED.equals(Environment
                    .getExternalStorageState())) {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                //         
                pd.setMax(conn.getContentLength());
                InputStream is = conn.getInputStream();
                String fileName = SD_FOLDER
                         + appName+".apk";
                File file = new File(fileName);
                //          
                if (!file.getParentFile().exists())
                    file.getParentFile().mkdirs();
                FileOutputStream fos = new FileOutputStream(file);
                BufferedInputStream bis = new BufferedInputStream(is);
                byte[] buffer = new byte[1024];
                int len;
                int total = 0;
                while ((len = bis.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                    total += len;
                    //        
                    pd.setProgress(total);
                }
                fos.close();
                bis.close();
                is.close();
                return file;
            } else {
                throw new IOException("    SD ");
            }
        }
    
        /**
         *   apk
         */
        private static void installApk(Context mContext, File file) {
            Uri fileUri = Uri.fromFile(file);
            Intent it = new Intent();
            it.setAction(Intent.ACTION_VIEW);
            it.setDataAndType(fileUri, "application/vnd.android.package-archive");
            it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//        
            mContext.startActivity(it);
        }
    
        /**
         *         (versionName)
         * 
         * @return         
         */
    
        private static double getLocalVersion(Context context) {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = null;
            try {
                info = manager.getPackageInfo(context.getPackageName(), 0);
            } catch (NameNotFoundException e) {
                Log.e(TAG, "          ,  :" + e.getMessage());
                return 0.0;
            }
    
            return Double.valueOf(info.versionName);
        }
        /** 
         * byte(  )      kb(   ) mb(   ) 
         *  
         * @param bytes 
         * @return 
         */  
        public static String bytes2kb(long bytes) {  
            BigDecimal filesize = new BigDecimal(bytes);  
            BigDecimal megabyte = new BigDecimal(1024 * 1024);  
            float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)  
                    .floatValue();  
            if (returnValue > 1)  
                return (returnValue + "MB");  
            BigDecimal kilobyte = new BigDecimal(1024);  
            returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)  
                    .floatValue();  
            return (returnValue + "KB");  
        }  
    }
    

    STEP 6: 앱 설치 완료 여부
    public class ApkInstallReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)){
                  long downloadApkId =intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                  installApk(context, downloadApkId);
            }
        }
    
        /**
         *   apk
         */
        private void installApk(Context context,long downloadApkId) {
            //     ID
            SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
            long downId =sp.getLong(DownloadManager.EXTRA_DOWNLOAD_ID,-1L);
            if(downloadApkId == downId){
                DownloadManager downManager= (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
                Uri downloadFileUri = downManager.getUriForDownloadedFile(downloadApkId);
                if (downloadFileUri != null) {
                Intent install= new Intent(Intent.ACTION_VIEW);
                install.setDataAndType(downloadFileUri, "application/vnd.android.package-archive");
                install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(install);
                }else{
                    Toast.makeText(context, "    ", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

    DownloadManager 다운로드 가 완료 되면 라디오 android. intent. action. DOWNLOAD 를 보 냅 니 다.COMPLETE 에서 라디오 수신 자 를 새로 만 들 면 다음 과 같이 설정 할 수 있 습 니 다.
    
                
                    
                
            
    

    총결산
    본 고 는 안 드 로 이 드 가 어떻게 간단하게 업데이트 효 과 를 실현 하 는 지 를 소개 했다. 주로 다음 과 같은 박문 을 참고 했다. 안 드 로 이 드 개발 실전 의 app 버 전 업데이트 가 더욱 상세 하 다. 제 가 언급 하지 않 은 부분 은 원 보 를 참조 하 시기 바 랍 니 다.

    좋은 웹페이지 즐겨찾기