安卓应用实现自动更新比较简单,这里跟大家介绍下。
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,所以可以很方便的给出运营同学可以操作的后台界面,如下:

注意红框内的元素,运营同学在上传时,是不允许修改的,而是由程序自动解析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 这个文件,具体大家可以在网上下载。
BIOS设置详解:BIOS究竟有哪些重要设置?
电脑的性能和稳定性在很大程度上依赖于其基本输入输出系统(......
阅读
win10开机黑屏很久才进入桌面
很多使用win10系统的小伙伴电脑遇到了一个问题,就开机黑屏了......
阅读
显示器无信号问题处理:为什么我的显示
显示器显示无信号的问题在电脑使用过程中并不罕见,这类情况......
阅读
翔升显卡支持个人送保吗
许多用户购买完显卡之后最为关心的就是售后服务了,因此许多......
阅读
idm下载器进行下载速度限制的方法
idm下载器为大家提供了非常强大的操作功能,其中可以在idm下载......
阅读
谷歌改进的 iPhone 在消息中
苹果电脑腾讯会议怎么共
麦乐鸡侠是谁
WinDynamicDesktop具有Windows
全新Windows10文件管理器:
个人电脑销量排行_2020年个
云闪付可以删除交易记录
QQ绑定闺蜜亲密关系操作教
《鬼谷八荒》更新后无法
王者荣耀钥匙口令怎么用
《木筏求生》锤子在哪?
华擎显卡sn码查询
映众显卡等级划分
显卡驱动安装与更新指南
steam平台为什么会提示10
Word入门动画教程:新建
WPS文字设置文档仅局部内
如何阻止iPhone连接Mac后自
Win7、Win8系统下图片不能预
迅捷(FAST)无线路由器怎么
d-link路由器+IPCAM应用配置
安卓6.0怎么看电池用量 AndroidM每毫安电量查看方法 Android手机是如何耗电的?虽然我们可以查看总App耗电情况,却无法获知具体是如何耗电的。在最新安卓6.0第三预览版中,Google加入了应...
次阅读
在vivo X5Max场景桌面中点击物理【任务键】,选择【经典桌面】即可退出。(如下图) 注 :更多精彩教程请关注 手机教程 栏目,手机数码群:296605639欢迎你的加入...
次阅读
1)打开三星S6的相机,点击【模式】。(如下图) 2)进入模式界面后,点击【间隔拍照】。(如下图) 3)点击【照相机】按钮,设备会以2秒为间隔拍摄4张照片。(如下图) 4)拍摄完成后,设备会...
次阅读
努比亚z17高配和低配的区别是什么?努比亚z17正式发布了,分为高配和低配版,下文介绍努比亚z17标配和高配版对比,一起和小乐哥来了解下吧!...
次阅读
1)打开vivo X5Max手机【设置】,点击【智能体感】,点击【Smart wake】。(如下图) 1 / 2 1 2 下一页 尾页...
次阅读
联通美卡多少钱?大家是不是也想知道这个新套餐呢?那么联通大小美卡套餐资费是怎么算呢?下面绿茶小豆子为详细介绍。...
次阅读
有时候,你发现通知栏有一条消息,然后就去点击它,那条通知消息竟然自动变成软件下载了,而且连停止按钮都没有,根本停不下来。还有一些App在桌面都不生成图标,直接在后台伪...
次阅读
Comet是加州一家名为CometCore的公司所研发的一款防水手机,而作为一款防水手机,Comet有一个最大的亮点,那就是它即使掉进水里了也不会下沉,而是会浮在水面上,因此,手机的主人不...
次阅读
安卓5.0系统怎么样?相信很多用户对于安卓5.0系统怎么样还不太清楚,下面小编来跟大家分享一下android5.0系统使用评测,感兴趣的可以过来看一下。 在全新的Android 5.0中,一款新的系统...
次阅读
华为路由A1畅享版多少钱?今天华为发布了两款路由器,华为路由A1畅享版是其中之一,那么华为路由A1畅享版配置怎么样呢?下面绿茶小豆子为大家详细介绍。...
次阅读
在今天的安卓手机使用教程中,小编将给大家分享的是安卓手机运行Ping命令进行手机测试的方法。可能很多网友都不熟悉ping命令,下面,就一起来看看ping命令在安卓手机中的神奇作用...
次阅读
楼主,你好。这些有些应用是不支持的。具体做法,请参考下文: 1)打开你要浮窗的应用,沿对角线方向拖动屏幕的左上角或右上角。(如下图) 2)点击小白点。(如下图) 3)点击【浮窗】按...
次阅读
显示tim移动在线是手机上使用了TIM版本的QQ登录的账号,所以会显示TIM在线。im是腾讯最新发布的一款轻量型QQ,主要是用来办公使用的。...
次阅读
华为平板m3青春版怎么样?大家是不是也想知道这款新平板性能如何呢?那么下面绿茶小豆子为大家带来华为平板m3青春版评测!...
次阅读
Android L是谷歌今年交出的答卷之一,除了采用新的设计语言,还横跨Android Wear、TV等多个平台,并收紧了部分平台的界面定制权限,可以了解到谷歌在移动平台上的一些战略变化。当然...
次阅读