当前位置: 移动技术网 > IT编程>移动开发>Android > Android App实现应用内部自动更新的最基本方法示例

Android App实现应用内部自动更新的最基本方法示例

2019年07月24日  | 移动技术网IT编程  | 我要评论

希捷是哪个国家的,女王骑奴,下载电驴

这只是初步的实现,并没有加入自动编译等功能。需要手动更改更新的xml文件和最新的apk。   
共涉及到四个文件!
一、客户端
androidupdatetestactivity:程序首页
main.xml:首页布局
update:更新类
softupdate_progress:更新等待界面

updage

package majier.test; 
 
import java.io.file; 
import java.io.fileoutputstream; 
import java.io.ioexception; 
import java.io.inputstream; 
import java.net.httpurlconnection; 
import java.net.malformedurlexception; 
import java.net.url; 
import java.util.hashmap; 
 
import javax.xml.parsers.documentbuilder; 
import javax.xml.parsers.documentbuilderfactory; 
 
import org.w3c.dom.document; 
import org.w3c.dom.element; 
import org.w3c.dom.node; 
import org.w3c.dom.nodelist; 
 
import android.app.alertdialog; 
import android.app.dialog; 
import android.app.alertdialog.builder; 
import android.content.context; 
import android.content.dialoginterface; 
import android.content.intent; 
import android.content.dialoginterface.onclicklistener; 
import android.content.pm.packagemanager.namenotfoundexception; 
import android.net.uri; 
import android.os.environment; 
import android.os.handler; 
import android.os.message; 
import android.view.layoutinflater; 
import android.view.view; 
import android.widget.progressbar; 
import android.widget.toast; 
 
public class update { 
  private static final int download = 1; 
  private static final int download_finish = 2; 
  private static final int connect_failed = 0; 
  private static final int connect_success = 1; 
  hashmap<string, string> mhashmap; 
  private string msavepath; 
  private int progress; 
  private boolean cancelupdate = false; 
  private context mcontext; 
  private progressbar mprogress; 
  private dialog mdownloaddialog; 
  private string mxmlpath; // 服务器更新xml存放地址 
 
  public update(context context, string xmlpath, string savepath) { 
    this.mcontext = context; 
    this.mxmlpath = xmlpath; 
    this.msavepath = savepath; 
  } 
 
  private handler mhandler = new handler() { 
    public void handlemessage(message msg) { 
      switch (msg.what) { 
      case download: 
        mprogress.setprogress(progress); 
        break; 
      case download_finish: 
        installapk(); 
        break; 
      default: 
        break; 
      } 
    }; 
  }; 
 
  /** 
   * 检查更新 
   */ 
  public void checkupdate() { 
    new thread(new runnable() { 
      @override 
      public void run() { 
        try { 
          url url = new url(mxmlpath); 
          httpurlconnection conn = (httpurlconnection) url 
              .openconnection(); 
          conn.setconnecttimeout(5000); 
          inputstream instream = conn.getinputstream(); 
          mhashmap = parsexml(instream); 
          message msg = new message(); 
          msg.what = connect_success; 
          handler.sendmessage(msg); 
        } catch (exception e) { 
          message msg = new message(); 
          msg.what = connect_failed; 
          handler.sendmessage(msg); 
        } 
      } 
    }).run(); 
  } 
 
  /** 
   * 访问服务器更新xml 
   */ 
  handler handler = new handler() { 
    @override 
    public void handlemessage(message msg) { 
      super.handlemessage(msg); 
      switch (msg.what) { 
      case connect_failed: 
        toast.maketext(mcontext, "访问服务器失败!", toast.length_short).show(); 
        break; 
      case connect_success: 
        if (null != mhashmap) { 
          int servicecode = integer.valueof(mhashmap.get("version")); 
          if (servicecode > getversioncode(mcontext)) { 
            shownoticedialog(); 
          } 
        } 
        break; 
      } 
    } 
  }; 
 
  /** 
   * 获取程序版本号 
   */ 
  private int getversioncode(context context) { 
    int versioncode = 0; 
    try { 
      versioncode = context.getpackagemanager().getpackageinfo( 
          mcontext.getpackagename(), 0).versioncode; 
    } catch (namenotfoundexception e) { 
      e.printstacktrace(); 
    } 
    return versioncode; 
  } 
 
  /** 
   * 是否更新提示窗口 
   */ 
  private void shownoticedialog() { 
    alertdialog.builder builder = new builder(mcontext); 
    builder.settitle("软件更新"); 
    builder.setmessage("检测到新版本,是否更新?"); 
    builder.setpositivebutton("更新", 
        new onclicklistener() { 
          @override 
          public void onclick(dialoginterface dialog, int which) { 
            dialog.dismiss(); 
            showdownloaddialog(); 
          } 
        }); 
 
    builder.setnegativebutton("取消", 
        new onclicklistener() { 
          @override 
          public void onclick(dialoginterface dialog, int which) { 
            dialog.dismiss(); 
          } 
        }); 
    dialog noticedialog = builder.create(); 
    noticedialog.show(); 
  } 
 
  /** 
   * 下载等待窗口 
   */ 
  private void showdownloaddialog() { 
    alertdialog.builder builder = new builder(mcontext); 
    builder.settitle("正在更新"); 
    final layoutinflater inflater = layoutinflater.from(mcontext); 
    view v = inflater.inflate(r.layout.softupdate_progress, null); 
    mprogress = (progressbar) v.findviewbyid(r.id.update_progress); 
    builder.setview(v); 
    builder.setnegativebutton("取消下载", 
        new onclicklistener() { 
          @override 
          public void onclick(dialoginterface dialog, int which) { 
            dialog.dismiss(); 
            cancelupdate = true; 
          } 
        }); 
    mdownloaddialog = builder.create(); 
    mdownloaddialog.show(); 
    downloadapk(); 
  } 
 
  /** 
   * 涓嬭浇apk鏂囦欢 
   */ 
  private void downloadapk() { 
    new downloadapkthread().start(); 
  } 
 
  /** 
   * 下载程序 
   */ 
  private class downloadapkthread extends thread { 
    @override 
    public void run() { 
      try { 
        if (environment.getexternalstoragestate().equals( 
            environment.media_mounted)) { 
 
          url url = new url(mhashmap.get("url")); 
          httpurlconnection conn = (httpurlconnection) url 
              .openconnection(); 
          conn.connect(); 
          int length = conn.getcontentlength(); 
          inputstream is = conn.getinputstream(); 
 
          file file = new file(msavepath); 
          if (!file.exists()) { 
            file.mkdir(); 
          } 
          file apkfile = new file(msavepath, mhashmap.get("name")); 
          fileoutputstream fos = new fileoutputstream(apkfile); 
          int count = 0; 
          byte buf[] = new byte[1024]; 
          do { 
            int numread = is.read(buf); 
            count += numread; 
            progress = (int) (((float) count / length) * 100); 
            mhandler.sendemptymessage(download); 
            if (numread <= 0) { 
              mhandler.sendemptymessage(download_finish); 
              break; 
            } 
 
            fos.write(buf, 0, numread); 
          } while (!cancelupdate); 
          fos.close(); 
          is.close(); 
        } 
      } catch (malformedurlexception e) { 
        e.printstacktrace(); 
      } catch (ioexception e) { 
        e.printstacktrace(); 
      } 
 
      mdownloaddialog.dismiss(); 
    } 
  }; 
   
  /** 
   * 安装apk 
   */ 
  private void installapk() { 
    file apkfile = new file(msavepath, mhashmap.get("name")); 
    if (!apkfile.exists()) { 
      return; 
    } 
 
    intent i = new intent(intent.action_view); 
    i.setdataandtype(uri.parse("file://" + apkfile.tostring()), 
        "application/vnd.android.package-archive"); 
    mcontext.startactivity(i); 
  } 
 
  private hashmap<string, string> parsexml(inputstream instream) 
      throws exception { 
    hashmap<string, string> hashmap = new hashmap<string, string>(); 
    // 实例化一个文档构建器工厂 
    documentbuilderfactory factory = documentbuilderfactory.newinstance(); 
    // 通过文档构建器工厂获取一个文档构建器 
    documentbuilder builder = factory.newdocumentbuilder(); 
    // 通过文档通过文档构建器构建一个文档实例 
    document document = builder.parse(instream); 
    // 获取xml文件根节点 
    element root = document.getdocumentelement(); 
    // 获得所有子节点 
    nodelist childnodes = root.getchildnodes(); 
    for (int j = 0; j < childnodes.getlength(); j++) { 
      // 遍历子节点 
      node childnode = (node) childnodes.item(j); 
      if (childnode.getnodetype() == node.element_node) { 
        element childelement = (element) childnode; 
        // 版本号 
        if ("version".equals(childelement.getnodename())) { 
          hashmap.put("version", childelement.getfirstchild() 
              .getnodevalue()); 
        } 
        // 软件名称 
        else if (("name".equals(childelement.getnodename()))) { 
          hashmap.put("name", childelement.getfirstchild() 
              .getnodevalue()); 
        } 
        // 下载地址 
        else if (("url".equals(childelement.getnodename()))) { 
          hashmap.put("url", childelement.getfirstchild() 
              .getnodevalue()); 
        } 
      } 
    } 
    return hashmap; 
  } 
} 

androidupdatetestactivity

package majier.test; 
 
import android.app.activity; 
import android.os.bundle; 
import android.os.environment; 
 
public class androidupdatetestactivity extends activity { 
  /** called when the activity is first created. */ 
  @override 
  public void oncreate(bundle savedinstancestate) { 
    super.oncreate(savedinstancestate); 
    setcontentview(r.layout.main); 
    update(); 
  } 
   
  private void update() { 
    string sdpath = environment.getexternalstoragedirectory() + "/"; 
    string msavepath = sdpath + "boiler/"; 
    update updatemanager = new update(this, 
        "http://localhost:8011/abcd.xml", msavepath); 
    updatemanager.checkupdate(); 
  } 
} 

main.xml

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="fill_parent" 
  android:layout_height="fill_parent" 
  android:orientation="vertical" > 
 
  <textview 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello" /> 
 
</linearlayout> 

softupdate_progress.xml

<?xml version="1.0" encoding="utf-8"?> 
<linearlayout 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  android:layout_width="fill_parent" 
  android:layout_height="wrap_content"> 
  <progressbar 
    android:id="@+id/update_progress" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    style="?android:attr/progressbarstylehorizontal" /> 
</linearlayout> 

每次生成新的apk前,需要修改系统的版本号。

2016324165959773.png (747×620)

修改version code 和version name。上面的代码可以看出,系统是根据version code来判断是否需要更新的。version name作为一个版本名称。
这里我建议version code从10开始,这样方面名称修改(1.1、1.2)。
修改完成后,生成系统。然后将apk文件放在服务端的文件下。

二、服务端
服务端主要是建立一个网址供用户下载apk。在iis上新建网站

http://localhost:8011/。将更新文件和更新的xml放在目录下。 

2016324170029494.png (663×72)

version.xml格式

<update> 
  <version>12</version> 
  <name>boilerandroid_1.1</name> 
  <url>http://192.168.0.33:8011/boilerandroid.apk</url> 
</update> 

version对应着新程序的version code;
name随便起名;
url对应apk的下载路径。

在这里有可能会遇见一个问题,访问url路径时iis报错。主要是因为iis并不认识apk,不知道如何处理。
这里我们在iis中新增安卓程序的mime类型,来使apk支持下载。
在“iis管理器”中查看所建立的网站——mime类型——添加。
文件扩展名:.apk
mime类型:application/vnd.android.package-archive

2016324170048657.png (360×222)

这样就可以下载了。
目前只是一个简单的自动更新程序。我们可以看出,其中版本号需要自己填写,而且要与xml中的对应,apk需要生成后放在更新网址下。
这么的人为操作,很容易造成失误。因此,接下来我们要研究下自动发布更新版本,并且版本号与svn对应,在提交svn后,自动改变程序的版本号。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网