<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Android on lategege 的技术博客</title><link>https://lategege.com/tags/android/</link><description>Recent content in Android on lategege 的技术博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 07 Dec 2022 08:17:55 +0000</lastBuildDate><atom:link href="https://lategege.com/tags/android/index.xml" rel="self" type="application/rss+xml"/><item><title>android studio开发系统应用配置</title><link>https://lategege.com/p/android-studio%E5%BC%80%E5%8F%91%E7%B3%BB%E7%BB%9F%E5%BA%94%E7%94%A8%E9%85%8D%E7%BD%AE/</link><pubDate>Wed, 07 Dec 2022 08:17:55 +0000</pubDate><guid>https://lategege.com/p/android-studio%E5%BC%80%E5%8F%91%E7%B3%BB%E7%BB%9F%E5%BA%94%E7%94%A8%E9%85%8D%E7%BD%AE/</guid><description>&lt;!-- wp:paragraph --&gt;
&lt;p&gt;一、配置系统签名,正常在build.gradle中配置即可（略)&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;二、将系统应用import进android studio变成gradle工程。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;三 、分析系统应用mk文件，查看依赖。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;四、在build.gradle中添加mk中的依赖，可以远程依赖，也可以去android系统编译目录查找，android系统编译目录为:out/soong/.intermediates.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;五、将framework.jar拷贝进工程libs目录，framework.jar在android编译目录 out/soong/.intermediates/frameworks/base/framework/android_common/combined，这个jar可以不限制使用android的系统api.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;六，配置framework.jar的gradle依赖，compileOnly只编译即可。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;七、在最外层build.gradle根目录中配置脚本，这一步是为了编译的时候以framework中的api优先编译.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;allprojects {
 repositories {
 maven { url 'https://maven.aliyun.com/repository/public' }
 google()
 }
&lt;pre&gt;&lt;code&gt;gradle.projectsEvaluated {
 tasks.withType(JavaCompile) {
 Set&amp;amp;lt;File&amp;amp;gt; fileSet = options.bootstrapClasspath.getFiles()
 List&amp;amp;lt;File&amp;amp;gt; newFileList = new ArrayList&amp;amp;lt;&amp;amp;gt;();
 //&amp;quot;../framework.jar&amp;quot; 为相对位置，需要参照着修改，或者用绝对位置
 newFileList.add(new File(&amp;quot;./app/libs/framework.jar&amp;quot;))
 newFileList.addAll(fileSet)
 options.bootstrapClasspath = files(
 newFileList.toArray()
 )
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;八、在最外层配置脚本,这一步告诉android studio 将android.jar配置到依赖末尾，使得android studio去优先使用framework.jar中的api，这个和上一步的用途是不一样的，上一步是为了编译，而这一步是为了android studio这个开发工具来配置的。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;gradle.buildFinished {
 pushDownAndroidSDK('./.idea/modules/app/xxxxx.app.iml')
}
&lt;p&gt;def pushDownAndroidSDK(iml){
def imlFile = file(iml)
try {
def parsedXml = (new XmlParser()).parse(imlFile)
def jdkIndexOf = parsedXml.component[1].orderEntry.findIndexOf { it.&amp;rsquo;@type&amp;rsquo; == &amp;lsquo;jdk&amp;rsquo; }
if (jdkIndexOf &amp;lt;= 1) {
def jdkNode =parsedXml.component[1].orderEntry.find { it.&amp;rsquo;@type&amp;rsquo; == &amp;lsquo;jdk&amp;rsquo; }
parsedXml.component[1].remove(jdkNode)
new Node(parsedXml.component[1], &amp;lsquo;orderEntry&amp;rsquo;,[&amp;rsquo;type&amp;rsquo;: &amp;lsquo;jdk&amp;rsquo;, &amp;lsquo;jdkName&amp;rsquo;: &amp;lsquo;Android API 28 Platform&amp;rsquo;, &amp;lsquo;jdkType&amp;rsquo;: &amp;lsquo;Android SDK&amp;rsquo;])
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(parsedXml)
imlFile.text = writer.toString()
println &amp;ldquo;Push File: $iml jdk priority ok&amp;rdquo;
groovy.xml.XmlUtil.serialize(parsedXml,new FileOutputStream(imlFile))
}
} catch (Exception e) {
// do nothing
}
}&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;!-- /wp:code --&gt;</description></item><item><title>android应用架构设计浅谈</title><link>https://lategege.com/p/android%E5%BA%94%E7%94%A8%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%E6%B5%85%E8%B0%88/</link><pubDate>Fri, 08 Apr 2022 09:43:48 +0000</pubDate><guid>https://lategege.com/p/android%E5%BA%94%E7%94%A8%E6%9E%B6%E6%9E%84%E8%AE%BE%E8%AE%A1%E6%B5%85%E8%B0%88/</guid><description>&lt;!-- wp:paragraph --&gt;
&lt;p&gt;在android app开发过程中，经常会遇到代码写着写着就非常臃肿，有时候改动了一处，引发了关联性灾难，这不由得让我们思考如何才能把代码写的更具有扩展性和可维护性，架构这个东西并没有最好，只有最合适。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;网上很多文章在写MVC、MVP、MVVM，组件化、插件化、单一职责、单例模式、工厂模式等，但是没有一篇是综合上述思想或者模式来谈架构设计。它们都属于架构的范畴，但是关注的维度不同。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;一、针对MVC、MVP、MVVM，它关心的是数据从获取到展示的代码逻辑，所要解决的核心问题是数据和界面之间如何更好联系的问题，它的侧重点是界面和数据。然而这三种设计模式在每个开发人员心中都有各自的理解，现在这些模式与发明人当初发明时所想表达思想已经不尽相同，即使在当下，后台开发人员和前端开发人员的理解也不一样，甚至在android开发中，每个人都有不同的见解，但是我们的目的都是一样的，那就是解耦和复用。下面会以大部分人认同的理解来阐述这三种模式的异同。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;MVC(model view controller) 在android中，model模型--默认就是业务数据层(包括业务数据的获取、以及数据本身)，view 默认指xml文件 ，controller默认指activity，这种理解方式多少受到了android框架本身的影响，activity这个和界面强相关的实体，数据展示逻辑以及事件处理逻辑放在其中是顺理成章的事，由此如果这个activity业务非常复杂，那么它必然会变得很臃肿，但是反过来诸如以下代码：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;public class GuidActivity : AppCompatActivity() {
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 //简单的逻辑
 startActivity(Intent(this,MainActivity.javaClass))
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;这是一个app启动界面GuidActivity，如果这个界面没有复杂的逻辑，这个时候采用默认的MVC又有何不可呢？配上注释，它的可读性非常强，针对这种场景，谁能说这样的代码不够优雅？所以做架构千万不要陷入误区，不要为了架构而架构。另外MVC在android中的上述解释其实非常牵强，因为activity严格来说也算做界面的一部分，所以这个view和controller的界限很模糊，基本上都融合在一起了，称它为M-VC一点都不为过，基于这个事实才诞生了MVP这种模式。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;MVP(model view presenter)MVP针对上面这种activity和xml界限模糊的问题做出了解决方案，它单独抽出了Presenter层，其本质还是Controller，但是这种模式将activity彻底抛到了view的一边，也就是无论是xml、自定义空间还是activity，它都是属于view层，而presenter层单独创建了，它替代了原来在activity中的职责，负责向model层拿数据，也负责将数据塞给view层，从而将model和view隔离开来，所以android中大部分人认为的MVP在本质上才是真正的MVC模式，就相当于原来的MVC其实是假冒伪劣产品一样，以下代码就是一个完整的MVP结构。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;class MVPActivity : AppCompatActivity() {
 var persenter: Presenter? = null;
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 persenter = Presenter(this)
 persenter!!.requestData()
 }
 fun show(data: String) {
 findViewById&amp;lt;TextView&amp;gt;(R.id.text).text = data
 }
}
class Presenter constructor(view: MVPActivity) {
 var model: Model = Model()
 var view: MVPActivity
 init {
 this.view = view
 }
 fun requestData() {
 view.show(model.getDataFromWork())
 }
}
class Model {
 fun getDataFromWork(): String {
 return "data"
 }
}&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;当view和model不再联系时，MVP所带来的好处是view和model的可替换性，以及单元测试的便利性，还做到了presenter的重用，因为presenter单独抽离了，由于项目中在不同页面可能需要相同的业务，这个时候preseneter的代码就可以复用了，但是要做复用上面的代码还不够，必须要将view接口化，使得presenter和activity彻底解绑，presenter持有抽象的view就足够了。而对于model的接口化，它的目的是里氏替换，数据源可以从网络获取，同样可以从缓存获取，这个时候策略模式就可以上场了，而presenter的接口化更多的目的是业务的重用，比如一个业务中包含业务A和业B，其实并不需要重写一个Presenter，只要实现这两个Presenter接口，并让它们对应的实现去干活就可以了，如果该业务有新增就在其中加入独有的业务逻辑。MVP设计模式在android中的缺点也很明显，那就是内存泄漏风险，当presenter持有了activity的引用，一个presenter中的model做了耗时操作的同时activity关闭了，此时activity就泄漏了，所以要更好的使用MVP还要加上activity生命周期的维护，还有就是如果项目中的业务相对独立又没有任何重叠，MVP这种模式就非常鸡肋了，它会造成接口泛滥，一套MVP接口只用一次的尴尬在这种情景下显得非常突出，它唯一起到的作用就是控制层彻底分离了，针对这种情景就不需要面向接口了，因为你定义的接口就用了一次，失去了接口本来的意义，还不如直接了当的写代码，会让整体代码显得更加清爽，针对MVP的内存泄漏这一点，其实也是谷歌推崇MVVM的原因之一。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;MVVM(model view viewmodel) 在MVVM中viewmodel有了感知生命周期的能力，它的本质还是控制层，只不过它没有持有view的引用，在这种模式多了一个数据绑定概念，谷歌为我们开发者提供好了绑定工具api--databinding，databinding(数据绑定)使得数据实体和xml绑定在一起，更新数据实体中的数据，xml界面就更新，它是视图绑定(viewbinding)和可观察数据对象(observable)两者合一的应用，而livedata是obervable的一种具备生命周期感知的应用，本质上它们是实现android mvvm的一整套工具，所以android中MVVM注重对谷歌工具的使用，感知这个概念贯穿整个模式中，这个感知包括activity、fragment的生命周期感知，也包含数据变化的感知，在具体的MVVM实现中，viewmodel通过model获取数据，获取到的数据包装成可感知的数据，view层对数据变化做监听，无论使用databinding也好，还是使用livedata也好，都是监听数据变化来更新UI，它和MVP的区别在于P将数据主动喂给V，而MVVM中的view是去监听数据的变化来触发更新。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;在MVVM中，正因为谷歌为我们提供了工具，所以代码量才没有MVP这种接口实现来的多，同时规避了MVP自动管理生命周期的尴尬，但是诸如使用databinding这种工具增加了代码的调试难度，同时编码过程中频繁在xml和java中切换，让xml文件含有数据逻辑处理本身就是一种耦合的表现，它并不利于xml文件的复用，databinding的使用场景应该是数据展示层变化较小同时数据展示纯粹(一个xml中绑定的实体数不多，但是实体中的数据数目较多时)的业务环境，大部分业务变化较快、数据结构多变的时候就不适合使用databinding，viewmodel+livedata+viewbinding是一个不错的选择。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;二、组件化、插件化在架构层面的侧重点是业务功能拆分，其中组件化是将应用按功能拆分不同组件或者模块，组件之间不再相互依赖，组件可以依赖同一套libray，组件化最大的好处是有利于团队开发，在团队开发中不需要等待别人的代码，自己可以进行独立测试，写库的写库，写模块的写模块，互不干涉，在android中一个组件对应着一个module，组件化还有一个好处就是可以提高编译效率。在大型项目中使用组件化是必要的，然而在一些独立开发的小型项目中使用组件化反而得不偿失，因为组件化多少会带来代码和配置增多。插件化核心在于动态加载模块，在庞大的工程中，可以按需下载功能包，它不是官方支持的，是一种取巧的技术，在国内盛行，因为android的开源，framework层代码对程序员透明，插件化是android开发者解决一个又一个的问题后诞生的，首先解决的是加载dex文件，android PathClassLoader就能解决，其次是资源文件的加载(res、assets、so) AssetsManager能解决，在资源加载的过程中还要考虑资源id重复或者找不到的问题，再次要解决activity清单文件注册问题，在分析framework后可以采用hook，也就是在调用ams时和ams返回后两个地方进行移花接木，插件化解决了初安装包体太大的问题，按需加载也解决了功能动态下发的问题，但是维护性很高，比如每个android新版本都要做兼容，甚至完全要看谷歌让不让用。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;组件化和插件化都是业务架构范畴，如何拆分更好的拆分业务才是核心。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;三、单一职责、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特原则是程序设计的六大原则，它是代码层面的编程思想，其中各种代码示例在我的另一篇文章有完整的体现。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;a href="https://blog.csdn.net/qq_28029345/article/details/68941819?spm=1001.2014.3001.5501" rel="noreferrer noopener" target="_blank"&gt;设计模式六大原则&lt;/a&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;这些原则是一种编程指导思想，目的是让程序员写出更容易扩展和维护的代码，如果程序设计比作做人，那么六大设计原则就是做人的道德规范，而23种设计模式就好比行为准则一样。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;四、23种设计模式&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:list {"ordered":true} --&gt;
&lt;ol&gt;&lt;li&gt;创建型设计模式&lt;br/&gt;与对象创建有关；共5种：单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式；&lt;br/&gt;单例模式&lt;br/&gt;6种单例模式.&lt;/li&gt;&lt;li&gt;结构型设计模式&lt;br/&gt;共7种：适配器模式、装饰模式、代理模式、外观模式、桥接模式、组合模式、享元模式。&lt;/li&gt;&lt;li&gt;行为型设计模式&lt;br/&gt;共11种：策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。、&lt;/li&gt;&lt;/ol&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;不管是设计原则还是设计模式，它们在架构设计中无处不在，每一种设计模式都有它适用的场景，比如项目中的管理类，管理大总管一般适合采用单例模式，一旦内存中出现了两个管理者，很可能产生混乱，建造者模式它的目的按需实例化一个对象，工厂模式的侧重点是屏蔽实例化对象的复杂性，原型模式侧重点是解决创建对象的成本问题。装饰者模式是为了增强类的能力而存在，代理模式其实是迪米特原则的体现，就是对象之间不能胡乱调用等等。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;架构切不可为了设计模式而设计模式，设计模式一定有它适用的场景，在实际开发中一定要随机应变，这才是真正的架构设计。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;</description></item><item><title>android 通过adb配置代理方式</title><link>https://lategege.com/p/android-%E9%80%9A%E8%BF%87adb%E9%85%8D%E7%BD%AE%E4%BB%A3%E7%90%86%E6%96%B9%E5%BC%8F/</link><pubDate>Mon, 18 Oct 2021 08:32:06 +0000</pubDate><guid>https://lategege.com/p/android-%E9%80%9A%E8%BF%87adb%E9%85%8D%E7%BD%AE%E4%BB%A3%E7%90%86%E6%96%B9%E5%BC%8F/</guid><description>&lt;!-- wp:paragraph --&gt;
&lt;p&gt;设置代理：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb shell settings put global http_proxy ip:port&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;如：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb shell settings put global http_proxy 192.168.0.5:8888&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;移除代理（需三条指令全部执行，部分机型可能需要重启手机才能完全移除代理）：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb shell settings delete global http_proxy&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb shell settings delete global global_http_proxy_host&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb shell settings delete global global_http_proxy_port&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;adb reboot&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;</description></item><item><title>android新一代模拟器cuttlefish</title><link>https://lategege.com/p/android%E6%96%B0%E4%B8%80%E4%BB%A3%E6%A8%A1%E6%8B%9F%E5%99%A8cuttlefish/</link><pubDate>Thu, 07 Oct 2021 11:06:41 +0000</pubDate><guid>https://lategege.com/p/android%E6%96%B0%E4%B8%80%E4%BB%A3%E6%A8%A1%E6%8B%9F%E5%99%A8cuttlefish/</guid><description>&lt;!-- wp:heading --&gt;
&lt;h2 id="what_is_cuttlefish"&gt;什么是 Cuttlefish？&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/"&gt;Cuttlefish&lt;/a&gt; 是一种可配置的虚拟 Android 设备，既可以远程运行（使用第三方云产品，如 Google Cloud Engine），又可以在本地运行（在 Linux x86 机器上）。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2 id="cuttlefish_goals"&gt;Cuttlefish 的目标&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:list --&gt;
&lt;ul&gt;&lt;li&gt;使平台和应用开发者不再依赖于物理硬件来开发和验证代码更改。&lt;/li&gt;&lt;li&gt;通过与核心框架保持高度一致，以&lt;strong&gt;高保真度&lt;/strong&gt;为重点来复制真实设备的基于框架的行为。&lt;/li&gt;&lt;li&gt;支持 API 级别 28 之后的所有 API 级别。&lt;/li&gt;&lt;li&gt;在各个 API 级别达到&lt;strong&gt;一致的&lt;/strong&gt;功能水平，与物理硬件上的行为保持一致。&lt;/li&gt;&lt;li&gt;实现规模化：&lt;ul&gt;&lt;li&gt;能够并行运行多台设备。&lt;/li&gt;&lt;li&gt;能够并发执行测试，实现高保真度且入门成本较低。&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;提供可配置的设备，能够调整设备类型、RAM、CPU 等。&lt;/li&gt;&lt;/ul&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2 id="comparing_cuttlefish_to_other_devices"&gt;Cuttlefish 与其他设备的对比情况&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 id="cuttlefish_and_android_emulator"&gt;Cuttlefish 和 Android 模拟器&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Cuttlefish 与 &lt;a href="https://source.android.google.cn/setup/create/avd"&gt;Android 模拟器&lt;/a&gt;有许多相似之处，但 Cuttlefish 可以保证 Android 框架（无论这是纯 AOSP，还是您自己的树中的自定义实现）实现全保真。在实际应用中，这意味着 Cuttlefish 应该会在操作系统级别响应您的互动，就像使用相同的自定义或纯 Android 操作系统源代码构建的实体手机目标一样。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Android 模拟器围绕简化应用开发的用例构建而成，它包含许多功能钩子来迎合 Android 应用开发者的用例。如果您要使用您的自定义 Android 框架来构建模拟器，这可能会带来一些挑战。如果您需要能够代表您的自定义平台/框架代码或 Android 树形结构的虚拟设备，那么 Cuttlefish 虚拟设备是理想的选择。它是用于表示当前 AOSP 开发状态的规范设备。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 id="cuttlefish_and_physical_device"&gt;Cuttlefish 和物理设备&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Cuttlefish 虚拟设备与物理设备之间的主要区别在于硬件抽象层 (HAL) 级别，以及与任何自定义硬件互动的任何软件。除了硬件专用实现之外，您应该会发现 Cuttlefish 和物理设备表现出在功能上等效的行为。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2 id="how_can_cuttlefish_help"&gt;Cuttlefish 有哪些益处？&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;您可以像与任何可能用于调试的其他 Android 设备互动一样与 Cuttlefish 互动。它会通过 adb 将自身注册为正常设备，您可以像与物理设备互动一样通过远程桌面与之互动。Cuttlefish 的用例非常广泛，涵盖应用测试、自定义系统构建测试等。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;由于 Cuttlefish 力求实现框架全保真，因此可用于对您的框架和/或应用进行功能测试，在测试中没有无法模拟的物理硬件依赖项。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading {"level":3} --&gt;
&lt;h3 id="how_is_cuttlefish_commonly_used_for_testing_today"&gt;目前 Cuttlefish 通常如何用于测试？&lt;/h3&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Cuttlefish 在测试方面的一些常见应用包括：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:list --&gt;
&lt;ul&gt;&lt;li&gt;CTS&lt;/li&gt;&lt;li&gt;框架合规性&lt;/li&gt;&lt;li&gt;持续集成测试&lt;/li&gt;&lt;li&gt;自定义测试套件&lt;/li&gt;&lt;/ul&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2 id="can_i_host_cuttlefish_in_the_cloud"&gt;我是否可以在云端托管 Cuttlefish？&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;可以，Cuttlefish 本身支持 Google Cloud，并计划支持其他云平台。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading {"level":1} --&gt;
&lt;h1&gt;Cuttlefish Getting Started&lt;/h1&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#Try-Cuttlefish"&gt;&lt;/a&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#try-cuttlefish"&gt;&lt;/a&gt;Try Cuttlefish&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:list {"ordered":true} --&gt;
&lt;ol&gt;&lt;li&gt;Make sure virtualization with KVM is available. grep -c -w "vmx\|svm" /proc/cpuinfo This should return a non-zero value. If running on a cloud machine, this may take cloud-vendor-specific steps to enable. For Google Compute Engine specifically, see the &lt;a href="https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances"&gt;GCE guide&lt;/a&gt;.&lt;/li&gt;&lt;/ol&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;ARM specific steps:&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:list --&gt;
&lt;ul&gt;&lt;li&gt;When running on an ARM machine, the most direct way is to check for the existence of &lt;code&gt;/dev/kvm&lt;/code&gt;. Note that this method can also be used to confirm support of KVM on any environment.&lt;/li&gt;&lt;li&gt;Before proceeding to the next step, please first follow &lt;a href="https://android.googlesource.com/device/google/cuttlefish/+/HEAD/multiarch-howto.md"&gt;the guide&lt;/a&gt; to adjust APT sources.&lt;/li&gt;&lt;/ul&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:list {"ordered":true,"start":2} --&gt;
&lt;ol start="2"&gt;&lt;li&gt;Download, build, and install the host debian package:sudo apt install -y git devscripts config-package-dev debhelper-compat git clone https://github.com/google/android-cuttlefish cd android-cuttlefish debuild -i -us -uc -b sudo dpkg -i ../cuttlefish-common_*_*64.deb || sudo apt-get install -f sudo usermod -aG kvm,cvdnetwork $USER sudo reboot The reboot will trigger installing additional kernel modules and applying udev rules.&lt;/li&gt;&lt;li&gt;Go to &lt;a href="http://ci.android.com/"&gt;http://ci.android.com/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Enter a branch name. Start with &lt;code&gt;aosp-master&lt;/code&gt; if you don‘t know what you’re looking for&lt;/li&gt;&lt;li&gt;Navigate to &lt;code&gt;aosp_cf_x86_64_phone&lt;/code&gt; and click on &lt;code&gt;userdebug&lt;/code&gt; for the latest build&lt;/li&gt;&lt;li&gt;Click on &lt;code&gt;Artifacts&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Scroll down to the OTA images. These packages look like &lt;code&gt;aosp_cf_x86_64_phone-img-xxxxxx.zip&lt;/code&gt; -- it will always have &lt;code&gt;img&lt;/code&gt; in the name. Download this file&lt;/li&gt;&lt;li&gt;Scroll down to &lt;code&gt;cvd-host_package.tar.gz&lt;/code&gt;. You should always download a host package from the same build as your images.&lt;/li&gt;&lt;li&gt;On your local system, combine the packages:mkdir cf cd cf tar xvf /path/to/cvd-host_package.tar.gz unzip /path/to/aosp_cf_x86_64_phone-img-xxxxxx.zip&lt;/li&gt;&lt;li&gt;Launch cuttlefish with:&lt;/li&gt;&lt;/ol&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;code&gt;$ HOME=$PWD ./bin/launch_cvd&lt;/code&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:list {"ordered":true,"start":11} --&gt;
&lt;ol start="11"&gt;&lt;li&gt;Stop cuttlefish with:&lt;/li&gt;&lt;/ol&gt;
&lt;!-- /wp:list --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;code&gt;$ HOME=$PWD ./bin/stop_cvd&lt;/code&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#Debug-Cuttlefish"&gt;&lt;/a&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#debug-cuttlefish"&gt;&lt;/a&gt;Debug Cuttlefish&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;You can use &lt;code&gt;adb&lt;/code&gt; to debug it, just like a physical device:&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;code&gt;$ ./bin/adb -e shell&lt;/code&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#Launch-Viewer-WebRTC"&gt;&lt;/a&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#launch-viewer-webrtc"&gt;&lt;/a&gt;Launch Viewer (WebRTC)&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;When launching with &lt;code&gt;---start_webrtc&lt;/code&gt; (the default), you can see a list of all available devices at &lt;code&gt;https://localhost:8443&lt;/code&gt; . For more information, see the WebRTC on Cuttlefish &lt;a href="https://source.android.com/setup/create/cuttlefish-ref-webrtc"&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:heading --&gt;
&lt;h2&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#Launch-Viewer-VNC"&gt;&lt;/a&gt;&lt;a href="https://android.googlesource.com/device/google/cuttlefish/#launch-viewer-vnc"&gt;&lt;/a&gt;Launch Viewer (VNC)&lt;/h2&gt;
&lt;!-- /wp:heading --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;When launching with &lt;code&gt;--start_vnc_server=true&lt;/code&gt; , You can use the &lt;a href="https://www.tightvnc.com/download.php"&gt;TightVNC JViewer&lt;/a&gt;. Once you have downloaded the &lt;em&gt;TightVNC Java Viewer JAR in a ZIP archive&lt;/em&gt;, run it with&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;&lt;code&gt;$ java -jar tightvnc-jviewer.jar -ScalingFactor=50 -Tunneling=no -host=localhost -port=6444&lt;/code&gt;&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;Click “Connect” and you should see a lock screen!&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;webRTC 下运行效果：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:image {"sizeSlug":"large"} --&gt;
&lt;figure class="wp-block-image size-large"&gt;&lt;img alt="" src="https://img.lategege.com:30443/images/web/2021/10-7/1.png"/&gt;&lt;/figure&gt;
&lt;!-- /wp:image --&gt;</description></item><item><title>ubuntu20.04编译android 11(R)</title><link>https://lategege.com/p/ubuntu20-04%E7%BC%96%E8%AF%91android-11-r/</link><pubDate>Sun, 03 Oct 2021 03:31:44 +0000</pubDate><guid>https://lategege.com/p/ubuntu20-04%E7%BC%96%E8%AF%91android-11-r/</guid><description>&lt;!-- wp:paragraph --&gt;
&lt;p&gt;因为我有一台12核24线程 64g内存的1.5T固态+1T机械的服务器，服务器安装了PVE虚拟机，昨天刚把PVE从6.4升级为7.0，然后就想着要编译android 11的源码，编译源码当然选择最新的长期支持版ubuntu，也就是目前的ubuntu20.04，于是官网下载了镜像文件，下载地址：&lt;a href="https://ubuntu.com/download/desktop"&gt;https://ubuntu.com/download/desktop&lt;/a&gt;，装桌面版是因为可以应对后面在图形化界面中很方便解决的问题。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;我给虚拟机分配了10个核心，16g内存，300g硬盘(固态)，安装过程略。因为我的家庭网络采用了双软路由方案（爱快+LEDE)，所以，你懂得，我不需要设置什么软件源，因为我畅通无阻，但是android 11 源码将近90g，走国外的话，这流量费用。。。所以下源码的时候我还是决定使用国内镜像下载。其他比如软件更新什么的那点流量就忽略不计了。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;PVE中装完ubuntu20.04，第一件事：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#不管三七二十一，所有软件更新到最新再说
sudo apt-get update &amp;amp;&amp;amp; upgrade
#安装vim 方便后面在终端编辑
sudo apt-get install vim
#安装ssh server 安装完后可以在本地电脑上ssh连接操作了
sudo apt-get install openssh-server
# 编辑ssh_config 将这个注释去掉 PasswordAuthentication yes 保存
vim /etc/ssh/ssh_config
#重启下ssh
sudo /etc/init.d/ssh restart&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;接着，在本地电脑的终端上&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#ssh登录ubuntu
ssh 用户名@ip
&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;安装编译android所有需要的依赖(以下的操作建议先安装screen，然后在screen中操作，因为这样可以保证退出终端后任务还继续执行，下次进来想要展示之前的命令窗口也非常方便，具体的screen用法参考我的 另一篇文章&lt;a href="https://lategege.com/p/mac终端下使用screen/" rel="noreferrer noopener" target="_blank"&gt;https://www.lategege.com/?p=254&lt;/a&gt; mac、linux下操作一摸一样)&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install tofrodos python python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install lib32z-dev ccache
sudo apt-get install libssl-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;这里要注意有坑，第一个坑是libesd0-dev 这个软件包 在ubuntu默认源中是没有的，所以要添加源然后更新下软件列表再安装&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;sudo vim /etc/apt/sources.list //在行尾添加下面这个源保存
deb http://archive.ubuntu.com/ubuntu/ trusty main universe restricted multiverse
&lt;p&gt;#安装libesd0-dev
sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install libesd0-dev&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;第二个坑是关于lib32ncurses5-dev的，这个包安装不上。在安装的时候发现要安装libncurses5-dev，但是我软件包都更新为最新版本的了，也就是libncurses5-dev 最新版本是6.2的，我查看了下/usr/lib/x86_64-linux-gnu  这个目录下的动态库，发现只有libncurses.so.6，这就是因为libncurses5-dev这个包太新了，已经更新到6.2了，所以没有libncurses.so.5，因为后面编译需要有libncurses.so.5，不然编译会报错，我想了下有两种方案:一种libncurses5-dev回退到5.9，但是其他也有可能有依赖，又因为libncurses.so.6依赖了libtinfo.so.6，所以干脆如下暴力处理(后面的编译报错问题解决)：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;cd /usr/lib/x86_64-linux-gnu
sudo cp libncurses.so.6 libncurses.so.5
sudo cp libtinfo.so.6 libtinfo.so.5&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#装完软件需要设置下git的用户名密码,可以随意，但是这步是必须的，因为拉android源码的时候会验证git是否设置的email和name 不设置就不让拉取，http.sslverify https.sslverify 也配置下，后面拉取https仓库有时候报验证证书失败，配了这两个后就不会报错了。
git config --global user.email "xxx@xxx.com"
git config --global user.name "xxx"
git config --global http.sslverify false
git config --global https.sslverify false&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;接着就是拉取源码了，谷歌建议在home目录建一个bin文件夹，源码下载到这里，当然这只是建议，这边就按照谷歌的建议来操作。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#在当前用户家目录创建bin文件夹
mkdir ~/bin
#将该目录写入环境变量
echo "PATH=~/bin:\$PATH" &amp;gt;&amp;gt; ~/.bash_profile
#刷新环境变量
source ~/.bash_profile&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;补充知识：环境变量分为/etc目录下全局的和每个用户下面独立的，每个用户独立的又有两处可以放，.bashrc 或者.bash_profile 因为.bashrc本身有很多代码，所以建议建立独立的.bash_profile文件存放环境变量。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#拉取谷歌的代码管理脚本repo
curl https://storage.googleapis.com/git-repo-downloads/repo &amp;gt; ~/bin/repo
#不能科学上网的 从清华镜像获取 两个都是一样的 curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo
#授权执行权限,repo本质就是一个python2的脚本
chmod a+x ~/bin/repo&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#初始化repo 就是设置url为镜像地址 android-11版本在不断更新，可以去https://source.android.google.cn/setup/start/build-numbers#source-code-tags-and-builds这个官网地址查看最新版本是多少，针对的设备是哪些，再决定拉取哪个代码。
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-11.0.0_r43
&lt;h2 id="如果提示无法连接到-gerritgooglesourcecom可以编辑-binrepo把-repo_url-一行替换成下面的"&gt;如果提示无法连接到 gerrit.googlesource.com，可以编辑 ~/bin/repo，把 REPO_URL 一行替换成下面的：
&lt;/h2&gt;&lt;h2 id="repo_url--"&gt;REPO_URL = &amp;lsquo;&lt;a class="link" href="https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/%27" target="_blank" rel="noopener"
 &gt;https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'&lt;/a&gt;
&lt;/h2&gt;&lt;p&gt;#由于清华大学镜像对并发是有限制的，这里就看自己测试下来能最大几个就填-jX
repo sync -j4 &amp;ndash;fail-fast &amp;ndash;force-sync&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;#拉完代码就是编译过程 固定的三个命令 按顺序执行 lunch 根据自己需要选择不通平台
. build/envsetup.sh
lunch aosp_x86-eng
make -j16&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;在我编译过程中还遇到一个坑 如下：&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;
&lt;!-- wp:code --&gt;
&lt;pre class="wp-block-code"&gt;&lt;code&gt;merge_zips.go:752: prebuilts/gradle-plugin/com/android/tools/lint/lint-api/26.5.0/lint-api-26.5.0.jar: zip: not a valid zip file
12:05:58 ninja failed with: exit status 1&lt;/code&gt;&lt;/pre&gt;
&lt;!-- /wp:code --&gt;
&lt;!-- wp:paragraph --&gt;
&lt;p&gt;我查找prebuilts/gradle-plugin下面的文件，发现文件都是0kb，也就是这个文件夹中的文件根本没有同步下来，所以我直接删掉gradle-plugin这个文件夹，然后再一次执行repo sync，它会将gradle-plugin重新下载，接着编译就没问题了。&lt;/p&gt;
&lt;!-- /wp:paragraph --&gt;</description></item></channel></rss>