实现安卓app自动更新功能实例方案android app自动更新)安卓app怎么自动更新,

  一般的安卓应用都会提供自动更新的功能,让用户方便使用最新的版本,现在我们来讲讲如何实现安卓应用自动更新的功能实例方案,方便大家学习。

  安卓应用实现自动更新比较简单,这里跟大家介绍下。

  1. web接口

  需要提供一个接口供客户端查询更新状态,并且在需要更新时,告知客户端新APK地址。

  接口参数如下:

  package 包名,因为有时候会出现同一个应用换包名打包的情况

  version 版本号,即android清单文件里面的versionCode

  channel 渠道号

  os 操作系统,android/ios。ios 这里仅作预留。

  之所以传入这些字段,是要在与服务器端的包匹配时,务必满足:

  package, channel, os 相等,并且服务器端的version 大于 客户端传入的version

  代码如下:

  os = request.GET.get(os)

  pkg_name = request.GET.get(package)

  channel = request.GET.get(channel)

  version = request.GET.get(version)

  if not os or not pkg_name or not channel or not version:

  return jsonify(**ret_dict)

  pkg = Package.objects.filter(

  os=os,

  package=pkg_name,

  channel=channel,

  status__gt=config.PACKAGE_STATUS_NOT_UPDATE

  ).order_by(-version).first

  if pkg and int(version) pkg.version:

  ret_dict[pkg_status] = str(pkg.status)

  ret_dict[pkg_url] = config.WEB_HOST + pkg.file.url

  ret_dict[update_prompt] = pkg.info

  return jsonify(**ret_dict)

  2. 数据库设计

  由于web端使用的是django,所以可以很方便的给出运营同学可以操作的后台界面,如下:

实现安卓app自动更新功能实例方案android app自动更新)安卓app怎么自动更新,插图

  注意红框内的元素,运营同学在上传时,是不允许修改的,而是由程序自动解析APK文件得到后填入的。

  具体的解析方法,我们稍后给出。

  而对应的models代码如下:

  class Package(models.Model):

  file = models.FileField(u文件, upload_to=config.PACKAGE_UPLOAD_PATH)

  package = models.CharField(u包名, max_length=255, blank=True, default=)

  version = models.IntegerField(u”版本号”, blank=True, default=0, null=True)

  channel = models.CharField(u”渠道”, max_length=128, blank=True, default=)

  status = models.IntegerField(u更新状态, default=config.PACKAGE_STATUS_NOT_UPDATE,

  choices=config.PACKAGE_UPDATE_STATUS)

  info = models.TextField(u通知信息, blank=True, null=True)

  os = models.CharField(u操作系统, max_length=64, default=config.PACKAGE_CLIENT_UNKNOW,

  choices=config.PACKAGE_CLIENT_OS, blank=True, null=True)

  def __unicode__(self):

  _,name = os.path.split(self.file.name)

  return name

  class Meta:

  unique_together = (package, version, channel, os)

  def save(self, * args, ** kwargs):

  # 文件上传成功后,文件名会加上PACKAGE_UPLOAD_PATH路径

  path,_ = os.path.split(self.file.name)

  if not path:

  if self.file.name.endswith(.apk):

  self.os = config.PACKAGE_CLIENT_ANDROID

  path = os.path.join(/tmp, uuid.uuid4.hex + self.file.name)

  # logger.error(path: %s, path)

  with open(path, wb+) as destination:

  for chunk in self.file.chunks:

  destination.write(chunk)

  info = parse_apk_info(path)

  os.remove(path)

  self.package = info.get(package, )

  self.version = info.get(version, 0)

  self.channel = info.get(channel, )

  elif self.file.name.endswith(ipa):

  self.os = config.PACKAGE_CLIENT_IOS

  super(self.__class__, self).save(*args, ** kwargs)

  def display_filename(self):

  _,name = os.path.split(self.file.name)

  return name

  display_filename.short_description = u”文件”

  3. APK文件解析

  def parse_apk_info(apk_path, tmp_dir=/tmp):

  ”””

  获取包名、版本、渠道:

  {version: 17, channel: CN_MAIN, package: ‘com.fff.xxx}

  :param apk_path:

  :return:

  ”””

  from bs4 import BeautifulSoup

  import os

  import shutil

  import uuid

  abs_apk_path = os.path.abspath(apk_path)

  dst_dir = os.path.join(tmp_dir, uuid.uuid4.hex)

  jar_path = os.path.abspath(os.path.join(os.path.dirname(__file__), apktool.jar))

  cmd = java -jar %s d %s %s % (jar_path, abs_apk_path, dst_dir)

  if isinstance(cmd, unicode):

  cmd = cmd.encode(utf8)

  # 执行

  os.system(cmd)

  manifest_path = os.path.join(dst_dir, AndroidManifest.xml)

  result = dict

  with open(manifest_path, r) as f:

  soup = BeautifulSoup(f.read)

  result.update(

  version=soup.manifest.attrs.get(android:versioncode),

  package=soup.manifest.attrs.get(package),

  )

  channel_soup = soup.find(meta-data, attrs={android:name: UMENG_CHANNEL})

  if channel_soup:

  result[channel] = channel_soup.attrs[android:value]

  shutil.rmtree(dst_dir)

  return result

  当然,正如大家所看到的,我们需要依赖于 apktool.jar 这个文件,具体大家可以在网上下载。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容