|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
更多»
x
顿时注册,交友更多老友,享用更多功效,让你轻松玩转社区。
您须要 登录 才可以下载或查看,没有帐号?当即注册
实现安卓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 这个文件,具体大师可以在网高低载。 |
|