Android App 版本更新实现
2016-06-18 21:38
756 查看
今天终于进行了一次在我来看真正的面试,终于能和工程师进行一次交流了,虽然聊了没几分钟,但让我足够让我知道自己是多无知的了。
嘚嘚嘚说正事吧:这两天注意到了App更新的步骤,然后就打算做一下。
一般版本更新都是通过一个远程的通知进行通知用户进行版本更新,然后就顺着这里开头进行了开始,因为自己没有服务器,也不会本地创建一个服务端进行测试,然后我就查了查推送,本来是想用腾讯的信鸽,当我看见那个网站的主页做的乱死了,果断退了,看来看去极光推送还是比较主流的。
如果你使用的Eclipce 那么版本的配置是放在AndroidManifest.xml中的。
这个versionName这个值只是让用户看到的,每家公司都有自己的命名的方式,随便写了,不会影响升级的。
在使用Service的时候:
这个不知道什么原因,看了看百度都告诉我没写权限,这个肯定不是的了,看看Google有人说API23的权限机制变化的问题,看了看API只看见了怎样在使用的过程中如何请求启动权限和判断是否运行了这个权限,别的还真没读出来。
![](http://img.blog.csdn.net/20160618212642735?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20160618212750996?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
![](http://img.blog.csdn.net/20160618212833966?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
源码:http://download.csdn.net/detail/csdnhejingzhou/9553537
嘚嘚嘚说正事吧:这两天注意到了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
相关文章推荐
- Android IPC进程间通讯机制
- android之定时器AlarmManager
- axis备忘
- Windows XP Service Pack 3 RC1 v.3244 winxp补丁3 提供下载
- Run As Service runassrv.exe 详细参数第1/2页
- 安装MySQL在最后的start service停住了解决方法
- android使用Messenger绑定Service的多种实现方法
- asp.net Web Service 接口大量数据传输解决方案
- Silverlight中动态获取Web Service地址
- android调用web service(cxf)实例应用详解
- 在Android中 获取正在运行的Service 实例
- ASP.NET State service状态服务的问题解决方法
- 卸载ZkeysPHP 后iis网站出现Service Unavailable 解决办法
- IIS Admin Service 服务因 2149647636 (0x80210514) 服务性错误而停止
- Service Temporarily Unavailable的503错误是怎么回事?
- 深入剖析Android系统中Service和IntentService的区别
- Android中Service服务详解(一)
- android教程之service使用方法示例详解
- SSB(SQLservice Service Broker) 入门实例介绍