<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Android &#8211; 张三太爷</title>
	<atom:link href="https://www.somedoc.net/tag/android/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.somedoc.net</link>
	<description>看前面，黑洞洞</description>
	<lastBuildDate>Thu, 13 Feb 2020 13:42:22 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.1</generator>

<image>
	<url>https://www.somedoc.net/wp-content/uploads/2016/12/cropped-dandycheung-1-32x32.jpg</url>
	<title>Android &#8211; 张三太爷</title>
	<link>https://www.somedoc.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>一次被迫的排查安卓编译问题</title>
		<link>https://www.somedoc.net/2020/02/13/%e4%b8%80%e6%ac%a1%e8%a2%ab%e8%bf%ab%e7%9a%84%e6%8e%92%e6%9f%a5%e5%ae%89%e5%8d%93%e7%bc%96%e8%af%91%e9%97%ae%e9%a2%98/</link>
					<comments>https://www.somedoc.net/2020/02/13/%e4%b8%80%e6%ac%a1%e8%a2%ab%e8%bf%ab%e7%9a%84%e6%8e%92%e6%9f%a5%e5%ae%89%e5%8d%93%e7%bc%96%e8%af%91%e9%97%ae%e9%a2%98/#respond</comments>
		
		<dc:creator><![CDATA[张三太爷]]></dc:creator>
		<pubDate>Thu, 13 Feb 2020 07:31:59 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[备忘录]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[问题解决]]></category>
		<guid isPermaLink="false">http://www.somedoc.net/?p=4324</guid>

					<description><![CDATA[下载了工程，里面有两个模块，一个是 app，一个是其依赖。工 <a href="https://www.somedoc.net/2020/02/13/%e4%b8%80%e6%ac%a1%e8%a2%ab%e8%bf%ab%e7%9a%84%e6%8e%92%e6%9f%a5%e5%ae%89%e5%8d%93%e7%bc%96%e8%af%91%e9%97%ae%e9%a2%98/" class="more-link">[&#8230;]</a>]]></description>
										<content:encoded><![CDATA[<p>下载了工程，里面有两个模块，一个是 app，一个是其依赖。工程时间距今也有两年了，而老夫的 Android Studio 却总是保持最新，所以最开始编译不顺是理所应当的事。不管是 support 库的版本还是 gradle 的版本，都基本应对了下来。</p>
<p>直到最后的一个问题。我们姑且把被依赖的工程称之为 sdk 工程。这个工程里除了常规的 Java 类以外，还有 native 层供调用的 .so 文件。app 中调用 sdk 中的 Java 类，并间接使用 .so 里的能力。但实际的情况是加载 .so 就会出现 UnsatisfiedLinkError。打开 .apk 安装包检查，发现 .so 文件没有被打入包内。</p>
<p>在 app 的 build.gradle 文件里，依赖的写法很正规：</p><pre class="crayon-plain-tag">dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    testImplementation 'junit:junit:4.13'
    implementation 'com.android.support:appcompat-v7:23.4.0'
    implementation project(':sdk-project-name')
}</pre><p>而且其中的 Java 类可以编译进入 app 也说明并非依赖完全失效。单独编译 sdk 工程，发现其产出为 .aar 包，而包里是有 .so 文件的，这一发现更使得情况具有迷惑性。</p>
<p>网上查阅资料，大都语焉不详。不过有一篇启发了我，在这里：<a href="https://blog.csdn.net/pang_gua/article/details/88196330">https://blog.csdn.net/pang_gua/article/details/88196330</a>，它主要讲 aar 如何被依赖。由于现在网络上的文章生命周期往往不可信赖，因此全文附于下，也方便引用讨论（原文作者为 pang_gua，版权归其所有；如有异议请联系我）：</p>
<hr />
<h3>项目依赖 aar 以及依赖嵌套 aar</h3>
<p>原创 pang_gua 发布于 2019-03-05 18:51:11</p>
<p>一、application 直接依赖 aar（单一依赖）</p>
<p>复制 aar 至 app/libs 目录，app/build.gradle 添加以下代码:</p><pre class="crayon-plain-tag">// 根节点下添加 repositories 节点
repositories {
    flatDir {
        dirs 'libs'
    }
}

// dependencies 节点内添加依赖
dependencies {
    // aar-name 为 application 要依赖的 aar 包的名称，不包含后缀。
    implementation(name: ‘aar-name’, ext: 'aar')
}</pre><p>二、application 依赖 library，library 依赖 aar（嵌套依赖）</p>
<p>（library 名称以下用 aarlibs 代替， library 内依赖的子 aar 名称用 sublib 代替）</p>
<p>复制 sublib.aar 至 aarlibs/libs 目录，aarlibs/build.gradle 添加以下代码:</p><pre class="crayon-plain-tag">// 根节点下添加 repositories 节点
repositories {
    flatDir {
        dirs 'libs'
    }
}

// dependencies 节点内添加依赖
dependencies {
    implementation(name: ‘sublib’, ext: 'aar')
}</pre><p><strong>[重点]</strong> 此时 aarlibs 作为 library 有两种使用方式：(1) 作为 module 被 application 依赖；(2) 打包为新的 aar 被 application 依赖。</p>
<p>下面分别展示两种依赖方式下 application 的配置（主要是为了在引用 library 的同时能让 library 内部的 aar 也生效）。</p>
<p>2.1 作为 module 被 application 依赖<br />
application/app/build.gradle 添加以下代码:</p><pre class="crayon-plain-tag">// 根节点下添加 repositories 节点
repositories {
    flatDir {
        dirs project(':aarlibs').file('libs')
    }
}

// dependencies 节点内添加依赖
dependencies {
    implementation project(':aarlibs')
}</pre><p>2.2 作为 aar 被 application 依赖</p>
<p>将 aarlibs.aar 和 sublib.aar 复制至 applicatioon/app/libs 目录。虽然 aarlibs/libs 目录已经包含 sublib.aar 了，但是项目的 libs 里也需要复制一份，否则报错找不到 sublib.aar 内部的 Class。不过经简单测试，apk 的体积并不会因为重复有一份 sublib.aar 而将其做双倍纳入 apk 体内。</p>
<p>application/app/build.gradle 添加以下代码:</p><pre class="crayon-plain-tag">// dependencies 节点内添加依赖
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar'])
}</pre><p>附：清除 aar 缓存</p>
<p>terminal 进入项目根目录<br />
cd .idea/libraries<br />
rm Gradle__xxxx_aar.xml<br />
Android Studio 点击 左上角 SyncProject 和 SyncFile 按钮</p>
<hr />
<p>让我灵光显现的，正是上文中的 2.2，当 aar 工程被依赖时，为了将其中的某些文件包含到最终目标包中，使用了个.file() 的指令。老夫依葫芦画瓢，在自己的 app 工程的 build.gradle 里增加了以下一级节点：</p><pre class="crayon-plain-tag">repositories {
    flatDir {
        dirs project(':sdk-project-name').file('jniLibs')
    }
}</pre><p>Sync 后检查编译结果，所有的 .so 就已经都乖乖地待在 .apk 安装包内了。:)</p>
<p>更新，另附一篇相关文章（原始链接为 <a href="https://www.jianshu.com/p/59fd653a54d2">https://www.jianshu.com/p/59fd653a54d2</a>，作者为“曾是放牛娃”）：</p>
<h3 class="_1RuRku">Gradle依赖详解</h3>
<div class="rEsl9f">
<div class="_2mYfmT"><span class="FxYr8x"><a class="_1OhGeD" href="https://www.jianshu.com/u/36f4d7bdae1c" target="_blank" rel="noopener noreferrer">曾是放牛娃</a></span> <time datetime="2018-11-18T04:13:16.000Z">2018.11.18 12:13:16</time></div>
</div>
<article class="_2rhmJa">之前对 Android Gradle 构建的依赖一直傻傻分不清，这段时间正好接入集团的一个二方库，踩了很多坑，也顺带把 Gradle 依赖这块搞清楚了，主要整理了下 Gradle 依赖的类型、依赖配置、如何查看依赖、依赖冲突如何解决。</p>
<h4>依赖类型</h4>
<p>dependencies DSL 标签是标准 Gradle API 中的一部分，而不是 Android Gradle 插件的特性，所以它不属于 Android 标签。<br />
依赖有三种方式，如下例：</p>
</article>
<p></p><pre class="crayon-plain-tag">apply plugin: 'com.android.application'

android { ... }

dependencies {
    // Dependency on a local library module
    implementation project(":mylibrary")

    // Dependency on local binaries
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Dependency on a remote binary
    implementation 'com.example.android:app-magic:12.3'
}</pre><p></p>
<ul>
<li>本地 library 模块依赖</li>
</ul>
<p></p><pre class="crayon-plain-tag">implementation project(":mylibrary")</pre><p>这种依赖方式是直接依赖本地库工程代码的（需要注意的是，mylibrary 的名字必须匹配在 settings.gradle 中 include 标签下定义的模块名字）。</p>
<ul>
<li>本地二进制依赖</li>
</ul>
<p></p><pre class="crayon-plain-tag">implementation fileTree(dir: 'libs', include: ['*.jar'])</pre><p>这种依赖方式是依赖工程中的 module_name/libs/ 目录下的 .jar 文件（注意 Gradle 的路径是相对于 build.gradle 文件来读取的，所以上面是这样的相对路径）。</p>
<p>如果只想依赖单个特定本地二进制库，可以如下配置：</p><pre class="crayon-plain-tag">implementation files('libs/foo.jar', 'libs/bar.jar')</pre><p></p>
<ul>
<li>远程二进制依赖</li>
</ul>
<p></p><pre class="crayon-plain-tag">implementation 'com.example.android:app-magic:12.3'</pre><p>上面是简写的方式，这种依赖完整的写法如下：</p><pre class="crayon-plain-tag">implementation group: 'com.example.android', name: 'app-magic', version: '12.3'</pre><p>group、name、version 共同定位一个远程依赖库。需要注意的点是，version 最好不要写成 &#8220;12.3+&#8221; 这种方式，除非有明确的预期，因为非预期的版本更新会带来构建问题。远程依赖需要在 repositories 标签下声明远程仓库，例如 jcenter()、google()、maven 仓库等。</p>
<h4>依赖配置</h4>
<p>目前 Gradle 版本支持的依赖配置有：implementation、api、compileOnly、runtimeOnly和annotationProcessor，已经废弃的配置有：compile、provided、apk、providedCompile。此外依赖配置还可以加一些配置项，例如 AndroidTestImplementation、debugApi 等等。</p>
<p>常用的是 implementation、api、compileOnly 等几个依赖配置，含义如下：</p>
<ul>
<li>implementation<br />
与 compile 对应，会添加依赖到编译路径，并且会将依赖打包到输出（.aar 或 .apk），但是在编译时不会将依赖的实现暴露给其他 module，也就是只有在运行时其他 module 才能访问这个依赖中的实现。使用这个配置，可以显著提升构建速度，因为它可以减少重新编译的 module 的数量。建议，尽量使用这个依赖配置。</li>
<li>api<br />
与 compile 对应，功能完全一样，会添加依赖到编译路径，并且会将依赖打包到输出（.aar 或 .apk），与 implementation 不同，这个依赖可以传递，其他 module 无论在编译时和运行时都可以访问这个依赖的实现，也就是会泄漏一些不应该使用的实现。举个例子，A 依赖 B，B 依赖 C，如果都是使用 api 配置的话，A 可以直接使用 C 中的类（编译时和运行时），而如果是使用 implementation 配置的话，在编译时，A 是无法访问 C 中的类的。</li>
<li>compileOnly<br />
与 provided 对应，Gradle 把依赖加到编译路径，编译时使用，不会打包到输出（.aar 或 .apk）。这可以减少输出的体积，在仅编译时需要、运行时可选的情况下，很有用。</li>
<li>runtimeOnly<br />
与 apk 对应，Gradle 添加依赖只打包到 .apk，运行时使用，但不会添加到编译路径。这个没有使用过。</li>
<li>annotationProcessor<br />
与 compile 对应，用于注解处理器的依赖配置，这个没用过。</li>
</ul>
<h4>查看依赖树</h4>
<p>可以通过运行依赖的 Gradle 任务，查看单个 module 或者这个 project 的依赖，如下：</p>
<ol>
<li>View -&gt; Tools Windows -&gt; Gradle（或者点击右侧的 Gradle 栏）；</li>
<li>展开 AppName -&gt; Tasks -&gt; android，然后双击运行 AndroidDependencies。运行完，就会在 Run 窗口打出依赖树了。</li>
</ol>
<h4>依赖冲突解决</h4>
<p>随着很多依赖加入到项目中，难免会出现依赖冲突，出现依赖冲突如何解决？</p>
<h5>定位冲突</h5>
<p>依赖冲突可能会报类似下面的错误：</p><pre class="crayon-plain-tag">Program type already present com.example.MyClass</pre><p>通过查找类的方式（command + O）定位到冲突的依赖，进行排除。</p>
<h5>如何排除依赖</h5>
<ul>
<li>dependencies 中排除（细粒度）</li>
</ul>
<p></p><pre class="crayon-plain-tag">compile('com.taobao.android:accs-huawei:1.1.2@aar') {
    transitive = true
    exclude group: 'com.taobao.android', module: 'accs_sdk_taobao'
}</pre><p></p>
<ul>
<li>全局配置排除</li>
</ul>
<p></p><pre class="crayon-plain-tag">configurations {
    compile.exclude module: 'cglib'
    // 全局排除原有的 tnet jar 包与 so 包分离的配置，统一使用 aar 包中的内容
    all*.exclude group: 'com.taobao.android', module: 'tnet-jni'
    all*.exclude group: 'com.taobao.android', module: 'tnet-so'
}</pre><p></p>
<ul>
<li>禁用依赖传递</li>
</ul>
<p></p><pre class="crayon-plain-tag">compile('com.zhyea:ar4j:1.0') {
    transitive = false
}

configurations.all {
    transitive = false
}</pre><p>还可以在单个依赖项中使用 @jar 标识符忽略传递依赖：</p><pre class="crayon-plain-tag">compile 'com.zhyea:ar4j:1.0@jar'</pre><p></p>
<ul>
<li>强制使用某个版本。如果某个依赖项是必需的，而又存在依赖冲突时，此时没必要逐个进行排除，可以使用 force 属性标识需要进行依赖统一。当然这也是可以全局配置的：</li>
</ul>
<p></p><pre class="crayon-plain-tag">compile('com.zhyea:ar4j:1.0') {
    force = true
}

configurations.all {
    resolutionStrategy {
        force 'org.hamcrest:hamcrest-core:1.3'
    }
}</pre><p></p>
<ul>
<li>在打包时排除依赖。先看一个示例：</li>
</ul>
<p></p><pre class="crayon-plain-tag">task zip(type: Zip) {
    into('lib') {
        from(configurations.runtime) {
            exclude '*unwanted*', '*log*'
        }
    }

    into('') {
        from jar from 'doc'
    }
}</pre><p>代码表示在打 zip 包的时候会过滤掉名称中包含“unwanted”和“log”的 jar 包。这里调用的 exclude 方法的参数和前面的例子不太一样，前面的参数多是 map 结构，这里则是一个正则表达式字符串。<br />
也可以使用在打包时调用 include 方法选择只打包某些需要的依赖项：</p><pre class="crayon-plain-tag">task zip(type: Zip) {
    into('lib') {
        from(configurations.runtime) {
            include '*ar4j*', '*spring*'
        }
    }

    into('') {
        from jar from 'doc'
    }
}</pre><p>主要是使用 dependencies 中排除和全局配置排除。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.somedoc.net/2020/02/13/%e4%b8%80%e6%ac%a1%e8%a2%ab%e8%bf%ab%e7%9a%84%e6%8e%92%e6%9f%a5%e5%ae%89%e5%8d%93%e7%bc%96%e8%af%91%e9%97%ae%e9%a2%98/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>正确引用 Android Support v7 兼容支持库</title>
		<link>https://www.somedoc.net/2014/10/03/%e6%ad%a3%e7%a1%ae%e5%bc%95%e7%94%a8-android-support-v7-%e5%85%bc%e5%ae%b9%e6%94%af%e6%8c%81%e5%ba%93/</link>
					<comments>https://www.somedoc.net/2014/10/03/%e6%ad%a3%e7%a1%ae%e5%bc%95%e7%94%a8-android-support-v7-%e5%85%bc%e5%ae%b9%e6%94%af%e6%8c%81%e5%ba%93/#respond</comments>
		
		<dc:creator><![CDATA[张三太爷]]></dc:creator>
		<pubDate>Fri, 03 Oct 2014 02:15:52 +0000</pubDate>
				<category><![CDATA[[未分类]]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[备忘]]></category>
		<category><![CDATA[开发]]></category>
		<category><![CDATA[技术]]></category>
		<guid isPermaLink="false">http://www.somedoc.net/?p=2956</guid>

					<description><![CDATA[这个问题昨天下午折腾了我老人家一下午，手动进行了各种组合，最 <a href="https://www.somedoc.net/2014/10/03/%e6%ad%a3%e7%a1%ae%e5%bc%95%e7%94%a8-android-support-v7-%e5%85%bc%e5%ae%b9%e6%94%af%e6%8c%81%e5%ba%93/" class="more-link">[&#8230;]</a>]]></description>
										<content:encoded><![CDATA[<p>这个问题昨天下午折腾了我老人家一下午，手动进行了各种组合，最终得以解决。现将步骤严格记录于此，以作备忘。</p>
<p>一、环境及前提<br />
1、Windows 7/Mac OS X 10.9；<br />
2、Eclipse 4.4.1（Luna）；<br />
3、ADT 23.0.3；<br />
4、Android Support Library 已经用 Android SDK Manager 下载完毕。</p>
<p>二、创建可引用的工程 android-support-v7-appcompat<br />
1、打开 eclipse，从 File 菜单选择 Import&#8230;；<br />
2、在想到中选择 Android 下的 Existing Android Code Into Workspace，点击 Next；<br />
3、点击 Root Directory 行尾的 Browse 按钮，选中 <SDK>\extra\android\compatibility\v7\appcompat，确定；<br />
4、在向导中点击 Finish，则一个名为 android-support-v7-appcompat 的工程会出现在 Package Explorer 中；<br />
5、在工程名上右击，打开关联菜单，选择 Properties；<br />
6、在 Properties 对话框左侧点选 Android 条目，此时右侧的 Project Build Target 列表中将列出 SDK 目录下所有已安装的条目，找到列表框下的 Is Library 的复选框（如果安装了很多版本的 SDK，则可能需要拖动滚动条才能看见此复选框）；<br />
7、将 Is Library 复选框点选为选中状态；<br />
8、点击 OK 确定。</p>
<p>三、配置要引用的工程<br />
1、在此工程名上，执行上面的 5、6 两个步骤；<br />
2、点击 Is Library 复选框下一行尾的 Add&#8230; 按钮，在弹出的 Project Selection 对话框中选中 android-support-v7-appcompat 并点击 OK 确认；<br />
3、点击 OK 关闭 Properties 对话框；<br />
4、至此，android-support-v7-appcompat.jar 应该出现在工程中的 Android Dependencies 文件夹下；<br />
5、而 Android Private Libraries 文件夹下则会出现 android-support-v7-appcompat.jar 和 android-support-v4.jar；<br />
6、请确保工程中没有以其他的形式对 5 中提到的两个 jar 进行引用设置；<br />
7、如果 eclipse 的 console 视图中出现类似于 styles_base.xml:24: error: Error retrieving parent for item: No resource found that matches the given name &#8216;android:Widget.Holo.ActionBar&#8217; 这样的错误，请将 AndroidManifest.xml 中的 minSdkVersion 和 targetSdkVersion 值调整为 7。</p>
<p>四、释疑和备注<br />
之所以要创建一个新的工程以供引用，主要原因在于 SDK 中提供的 jar 需要额外的资源文件，这些资源文件会被新工程包含进来，这样才能被引用工程使用到。</p>
<p>开始一直失败，主要在于 三.2 的步骤没有正确执行，而是一直在 Java Build Path 中配置；而没有正确执行的主要原因就在于三太爷的 SDK 版本太全，以至于 Project Build Target 列表把 Is Library 撑到了可视范围之外。基于此，还一度怀疑被引用的工程创建的有问题，在 Import 环节上做了很多次尝试，例如选择 General 下的 Archive 模式或者 Existing Projects Into Workspace，由此更是走到了邪路上。</p>
<p>要验证在引用的工程中配置是否正确非常简单，查看 三.4 和 三.5 中的三个文件的路径即可。对于 Android Dependencies 文件夹下的 android-support-v7-appcompat.jar，它是被引用的工程的输出，因此鼠标指针悬停于其上时，补全显示的全路径最后应该是 bin；而 Android Private Libraries 文件夹下的 android-support-v7-appcompat.jar 和 android-support-v4.jar，是被引用工程的引用，因此其显示的全路径最后应该是 libs，位于 SDK 目录之下。当然，更简单的验证方法就是工程是否能够编译成功。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.somedoc.net/2014/10/03/%e6%ad%a3%e7%a1%ae%e5%bc%95%e7%94%a8-android-support-v7-%e5%85%bc%e5%ae%b9%e6%94%af%e6%8c%81%e5%ba%93/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
