您的位置:首页 > 移动开发

Android App 版本更新实现

2016-06-18 21:38 756 查看
今天终于进行了一次在我来看真正的面试,终于能和工程师进行一次交流了,虽然聊了没几分钟,但让我足够让我知道自己是多无知的了。

嘚嘚嘚说正事吧:这两天注意到了App更新的步骤,然后就打算做一下。

一般版本更新都是通过一个远程的通知进行通知用户进行版本更新,然后就顺着这里开头进行了开始,因为自己没有服务器,也不会本地创建一个服务端进行测试,然后我就查了查推送,本来是想用腾讯的信鸽,当我看见那个网站的主页做的乱死了,果断退了,看来看去极光推送还是比较主流的。

一、关于App版本设置的问题

新版本可以替换老版本的条件还是非常苛刻的,包名一致,生成时签名一样,sha1应该也是必须一致的。
如果你使用的Eclipce 那么版本的配置是放在AndroidManifest.xml中的。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hejingzhou.appversionsdatedemo"
android:versionCode="1"
android:versionName="1.1.1">
如果你使用的Android Studio 那么版本的配置在build.gradle中。
defaultConfig {
applicationId "com.hejingzhou.appversionsdatedemo"
minSdkVersion 15
targetSdkVersion 23
versionCode 2
versionName "1.0.1"
}
当你每次升级的时候versionCode  (整形的) 新版本必须比老版本的值大,否则会替换失败的。
这个versionName这个值只是让用户看到的,每家公司都有自己的命名的方式,随便写了,不会影响升级的。

二、关于这个极光推送接口就不大说了根据官方的文档来就行,需要做的也就是创建一个广播接收类。

package com.hejingzhou.appversionsdatedemo;

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import org.json.JSONObject;
import cn.jpush.android.api.JPushInterface;

/**
* Created by Hejingzhou on 2016/6/15.
*/
public class BroadcastReceiver extends android.content.BroadcastReceiver{
private String TAG = "Debug";
private NotificationManager manager;

@Override
public void onReceive(Context context, Intent intent) {
if(manager == null){
manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
Bundle bundle = intent.getExtras();
if(intent.getAction().equals(JPushInterface.ACTION_REGISTRATION_ID)){
Log.d(TAG,"用户注册成功");
}else if(intent.getAction().equals(JPushInterface.ACTION_MESSAGE_RECEIVED)){
Log.d(TAG,"接收到自定义的消息");
}else if(intent.getAction().equals(JPushInterface.ACTION_MESSAGE_RECEIVED)){
Log.d(TAG,"接受到推送下来的消息");
//receivingNotification(context,bundle);
}else if(intent.getAction().equals(JPushInterface.ACTION_NOTIFICATION_OPENED)){
Log.i(TAG,"用户打开了通知");
openNotification(context,bundle);
}
}

/***
* 打开通知要处理的方法
* @param context
* @param bundle
*/
private void openNotification(Context context, Bundle bundle){
String extras = bundle.getString(JPushInterface.EXTRA_EXTRA);
String versionsUrl = "";
try {
JSONObject extrasJson = new JSONObject(extras);
versionsUrl = extrasJson.optString("DownloadDate");
Log.i(TAG,"收到key为 one的数据    "+versionsUrl);
if(!versionsUrl.equals("")){
MainActivity.IS = true;
Log.i(TAG,"有更新数据");
Intent intent = new Intent(context,DownService.class);
intent.putExtra("DateUrl",versionsUrl);
context.startService(intent);
}
} catch (Exception e) {
Log.i(TAG, "Unexpected: extras is not a valid json", e);
return;
}

}
}
然后再补全AndroidManifest.xml的服务名称就行。

三、创建一个Service进行后台下载的过程,用户没必要看到的。

package com.hejingzhou.appversionsdatedemo;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;

/**
* Created by Hejingzhou on 2016/6/15.
*/
public class DownService extends Service {
private String TAG = "Debug";
private ServiceAndroidContact serviceAndroidContact = new ServiceAndroidContact();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"运行到了服务阶段");
final String downUrl = intent.getExtras().getString("DateUrl");
Log.i(TAG,downUrl);
new Thread(new Runnable() {
@Override
public void run() {
DownloadFile downloadFile = new DownloadFile();
try {
downloadFile.downloadFile(downUrl,"","DateApp.apk");
} catch (IOException e) {
e.printStackTrace();
}
if(!Thread.currentThread().isAlive()){
Log.i(TAG,"Thread Over");
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
return serviceAndroidContact;
}
}
在使用继承Service的服务 或者 继承BroadcastReceiver的广播接收的时候一定要记得在AndroidManifest.xml中进行注册:
在使用Service的时候:
<service android:name=".DownService"/>
在使用BroadcastReceiver的时候:
<receiver android:name=".ReceiverBroadCast">
<intent-filter>
<action android:name="com.hejingzhou.broadcast"/>
</intent-filter>
</receiver>

四、FileUtil  下载辅助(文件操作)

package com.hejingzhou.appversionsdatedemo;

import android.os.Environment;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
* Created by Hejingzhou on 2016/6/16.
* 创建文件  写流操作  判断文件是否存在
*/
public class FileUtils {
private String SDPATH;

public FileUtils() {
SDPATH = Environment.getExternalStorageDirectory() + "/";
}

public File createSdFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.createNewFile();
Log.i("Debug", file.getAbsolutePath());
return file;
}

public File createSdDir(String dirName) {
File dir = new File(SDPATH + dirName);
dir.mkdir();
return dir;
}

public boolean isFileExist(String fileName) {
File file = new File(SDPATH + fileName);
file.delete();
return file.exists();
}

public File writeToSdFromInput(String path, String fileName, InputStream inputStream) throws IOException {
MainActivity.IS = true;
File file;
OutputStream outputStream;
createSdDir(path);
file = createSdFile(path + fileName);
outputStream = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
Log.d("@@","@@");
outputStream.flush();
inputStream.close();
outputStream.close();
return file;
}

}<span style="color:#ff0000;">
</span>

五、文件下载

package com.hejingzhou.appversionsdatedemo;

import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
* Created by Hejingzhou on 2016/6/16.
*/
public class DownloadFile {
private URL url = null;
public int downloadFile(String url,String path,String fileName) throws IOException {
InputStream inputStream ;
FileUtils fileUtils = new FileUtils();
if(fileUtils.isFileExist(path+fileName)){//如果存在
Log.i("Debug","  "+"1");
return 1;
}else{
inputStream = getInputStreamFromUrl(url);
File requltFile = fileUtils.writeToSdFromInput(path,fileName,inputStream);
if(requltFile == null){ //下载失败
Log.i("Debug","  "+"-1");
return  -1;
}
}
if(inputStream!=null) inputStream.close();
Log.i("Debug","  "+"0");
return 0;//成功
}

private InputStream getInputStreamFromUrl(String urlPath) throws IOException {
url = new URL(urlPath);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
return urlConnection.getInputStream();
}

}
向SD卡写数据的时候别忘了写权限,在API23后,即使你写了权限,但是在虚拟机上运行的时候仍会报权限错误,但是你在真机调试的时候确实文件已经正常下载下来了。
这个不知道什么原因,看了看百度都告诉我没写权限,这个肯定不是的了,看看Google有人说API23的权限机制变化的问题,看了看API只看见了怎样在使用的过程中如何请求启动权限和判断是否运行了这个权限,别的还真没读出来。

六、MianActivity没什么用主要是安装指定路径的软件。

package com.hejingzhou.appversionsdatedemo;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import cn.jpush.android.api.JPushInterface;

public class MainActivity extends AppCompatActivity {
private Button btnIntallAp,btnServiceActivity;
static Boolean IS = false;
private ServiceAndroidContact serviceAndroidContact = new ServiceAndroidContact();

ServiceConnection coon = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serviceAndroidContact.Log();
}

@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnIntallAp = (Button) findViewById(R.id.buttonIntall);
btnServiceActivity = (Button)findViewById(R.id.buttonServiceActivity);
//Service与Activity交互
btnServiceActivity.setOnClickListener(new View.OnClickListener() {//这个Button并没有什么用只是自己测试Service与Activity交互。
@Override
public void onClick(View v) {
Intent intent = new Intent();
//intent.setAction("com.hejingzhou.startService");
intent.setPackage(getPackageName());
bindService(intent,coon,BIND_AUTO_CREATE);
}
});
if (IS == true) {
/*String path = Environment.getExternalStorageDirectory() + "/DateApp.apk";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
startActivity(intent);*/
IS = false;
}

btnIntallAp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

//测试是否安装安装了某个软件  通过包名
Boolean IIII = isPkgInstalled("com.hejingzhou.appversionsdatedemo");
Log.i("@@@@@",IIII+"");
Toast.makeText(getApplicationContext(),IIII+"",Toast.LENGTH_SHORT).show();

//安装指定的软件
String path = Environment.getExternalStorageDirectory() + "/DateApp.apk";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)), "application/vnd.android.package-archive");
startActivity(intent);
}
});
initJPush();
}

/***
* 检查是否存在某个App存在
* @param pkgName
* @return
*/
private boolean isPkgInstalled(String pkgName) {
PackageInfo packageInfo = null;
try {
packageInfo = this.getPackageManager().getPackageInfo(pkgName, 0);
} catch (PackageManager.NameNotFoundException e) {
packageInfo = null;
e.printStackTrace();
}
if (packageInfo == null) {
return false;
} else {
return true;
}
}
private void initJPush() {
JPushInterface.init(getApplicationContext());
JPushInterface.setDebugMode(true);
}
}<span style="color:#ff0000;">
</span>

七、如果读这个代码的时候,你会发现少一个类,这个类并没有什么用,我只是测试Service与Activity交互的类。

package com.hejingzhou.appversionsdatedemo;

import android.os.Binder;
import android.util.Log;

/**
* Created by Hejingzhou on 2016/6/17.
*/
public class ServiceAndroidContact extends Binder {
public void Log(){
Log.i("Debug","我是Activity和Service交互相应结果");
}
}
效果:







源码:http://download.csdn.net/detail/csdnhejingzhou/9553537
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息