查看: 12605981|回复: 0

实现安卓app主动更新功效实例计划

[复制链接]

14

主题

14

帖子

42

积分

新手上路

Rank: 1

积分
42
QQ
发表于 2015-3-8 11:22:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?立即注册 更多»

x
顿时注册,交友更多老友,享用更多功效,让你轻松玩转社区。

您须要 登录 才可以下载或查看,没有帐号?当即注册

                               
登录/注册后可看大图

实现安卓app主动更新功效实例计划

实现安卓app主动更新功效实例计划

x  一般的安卓利用城市供给主动更新的功效,让用户便利应用最新的版本,此刻我们来讲讲若何实现安卓利用主动更新的功效实例计划,便利大师进修。
  安卓利用实现主动更新比拟简略,这里跟大师先容下。
  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)
  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,所以可以很便利的给出运营同窗可以操纵的后台界面,如下:
1e7c6ecdaf2690156df68c36be434131.png

                               
登录/注册后可看大图

  留意红框内乱的元素,运营同窗在上传时,是不答应修正的,而是由法式主动解析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 这个文件,具体大师可以在网高低载。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 更多»

本版积分规则

快速回复 返回顶部 返回列表