最近项目里的采用免费的Bugly应用升级功能,由于默认的 UI 非常的简陋且与项目整体风格不搭,所以需要自定义UI,本篇文章记录在实现过程中的一些注意事项。根据官方文档可知,自定义升级界面有以下两种方式。
这种方式比较简单,只需要自己编写布局,并设置控件的Tag 即可。
<TextView
android:layout_width="match_parent"
android:layout_height="@dimen/dp_62"
android:gravity="center"
android:tag="beta_title" //按要求设置Tag即可
android:textSize="@dimen/sp_16"
android:textColor="@color/white"
android:text="发现新版本"/>
这里有个需要注意的地方就是beta_title beta_upgrade_info beta_upgrade_feature beta_cancel_button beta_confirm_button 这几个控件 Tag 缺一不可,缺了会导致整个页面是黑色的。
通过以上设置,基本就可以展示自己的 UI 了,但随即也会发现一个问题:状态栏是黑色,下方还有一条灰色的类似 ActionBa r的东西。
查阅文档发现,可以注 Bugly 弹窗的生命周期回调,如下所示。
Beta.upgradeDialogLifecycleListener = object :UILifecycleListener<UpgradeInfo>{
override fun onCreate(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
override fun onStart(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
override fun onResume(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
override fun onPause(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
override fun onStop(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
override fun onDestroy(p0: Context?, p1: View?, p2: UpgradeInfo?) {
}
}
对应的就是 BetaActivity 的生命周期,于是只需要在 onCreate 回调中,设置沉浸式状态即可。
至于怎么设置可以按照自己项目里的来,我设置了沉浸式,但有一条灰色的还是去不掉。而且这个方式无法满足我
们项目产品的要求,需要有进度条显示。于是可以用另外一种自定义 Activity的方式。
使用这种方式虽然比第一种稍微复杂了一点点🤏,但是可定制的范围却大了很多。弹窗界面的绘制与生命周期均由自己维护,Bugly 负责下载时回调与事件上报,并提供相关接口控制任务下载,获取任务状态等。
Beta.upgradeListener = object : UpgradeListener {
override fun onUpgrade(p0: Int, p1: UpgradeInfo?, p2: Boolean, p3: Boolean) {
p1?.let {
startActivity(Intent(applicationContext, UpdateActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
}
}
注意这一步要写在 init 之前。在这里判断了 如果 UpgradeInfo 不会null的话,说明有更新了,于是跳转到自定义的 Activity 即可。
更新一般都是弹窗,然后我们跳转到 Activity,就无法看见下方 Activity,跳转动画也比较生硬,符合习惯的应该是像普通弹窗一样弹出即可。所以这里需要将 Activity Dialog化。
只需要自定义一个 Style 即可,如下。
<style name="updateStyle" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowFrame">@null</item>
<!-- 半透明 -->
<item name="android:windowIsTranslucent">true</item>
<!-- 无标题 -->
<item name="android:windowNoTitle">true</item>
<!-- 背景透明 -->
<item name="android:windowBackground">@color/transparent</item>
<!-- 是否允许对话框的背景变暗 -->
<item name="android:backgroundDimEnabled">true</item>
</style>
然后给自定义的Activity设置上即可。
<activity
android:name=".activity.setting.UpdateActivity"
android:exported="false"
android:theme="@style/updateStyle"
android:screenOrientation="portrait"/>
如图所示,Activity 已经变得和 Dialog 一模一样了。
val upgradeInfo = Beta.getUpgradeInfo()
binding.run {
if (upgradeInfo.upgradeType==2){//如果是强制升级
betaCancelButton.gone()//隐藏下次再说按钮
}
betaUpgradeFeature.text = upgradeInfo.newFeature //显示更新内容
}
UpgradeInfo 包含如下信息,如果是强制升级的话,需要隐藏相应按钮,并且屏蔽掉返回按键。
public String id = "";//唯一标识
public String title = "";//升级提示标题
public String newFeature = "";//升级特性描述
public long publishTime = 0;//升级发布时间,ms
public int publishType = 0;//升级类型 0测试 1正式
public int upgradeType = 1;//升级策略 1建议 2强制 3手工
public int popTimes = 0;//提醒次数
public long popInterval = 0;//提醒间隔
public int versionCode;
public String versionName = "";
public String apkMd5;//包md5值
public String apkUrl;//APK的CDN外网下载地址
public long fileSize;//APK文件的大小
pubilc String imageUrl; // 图片url
var strategyTask = Beta.getStrategyTask()
在 strategyTask 对象中,我们可以判断之前是否已经下载完了。
strategyTask?.let {
if (it.saveFile!=null){
betaCancelButton.gone()
betaConfirmButton.text = "安装"
isFileSave = true
}
}
如果存在之前下载好但没安装的 Apk ,就可以直接去安装即可。
Beta.installApk(strategyTask?.saveFile)
//首先 Activity 实现 DownloadListener 接口
class UpdateActivity : AppCompatActivity(), DownloadListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Beta.registerDownloadListener(this)//注册下载事件回调
}
override fun onDestroy() {
super.onDestroy()
Beta.unregisterDownloadListener()//取消监听下载事件
}
override fun onBackPressed() {
//屏蔽返回按钮
}
//下载接收中
override fun onReceive(p0: DownloadTask?) {
p0?.let { binding.pb.setProgress(((it.savedLength.toDouble()/it.totalLength.toDouble())*100).toInt())
}
}
//下载完成
override fun onCompleted(p0: DownloadTask?) {
binding.betaConfirmButton.text = "安装"
binding.betaConfirmButton.isClickable = true
isFileSave = p0?.saveFile!=null
}
//下载失败
override fun onFailed(p0: DownloadTask?, p1: Int, p2: String?) {
}
}
我们先注册回调,直接调用Beta.startDownload()就可以开始下载了,在onReceive 中可以获取下载进度。下载完成后会自定安装。也可以设置 Beta.autoInstallApk = false手动安装
在 App 关于中,一般都有一个版本显示,点击可以手动检查更新,或者又更新的话显示一个小红点提醒用户去点击,用Bugly其实也可以实现,步骤如下。
Beta.getUpgradeInfo()?.let {
ivRedDot.show()
}?:let { ivRedDot.gone() }
获取升级信息,不为null就说明又更新策略,显示小红点即可。
下面是点击检查升级,注意第二个参数,是是否显示弹窗。
rlCheckUpdate.click {
Beta.checkUpgrade(true,false)
}
以上就是关于 Bugly 应用升级相关功能的实现记录。

我正在使用i18n从头开始构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在rubyonrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此
我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r
刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun