• GMS 简介
    • 集成 GMS 到 Android源码
    • GMS OVERRIDES OVERLAY 机制
    • GMS 覆盖 源码中的 webviewchromium
    • 单独升级某个 GMS 应用问题
    • 查看编译生成的GMS应用
    • GMS应用定制修改

GMS 简介

GMS 的全称是 Google Mobile Services (GMS) 。它是 Google 开发的一系列 apk集合,这些 apk 都或多或少的依赖 Google 服务。它没有包含在 Android 的开源代码中,当然也就不能看到这些 apk 的实现代码。在整机开发中,如果目标客户是国外用户,那么往往就需要预制GMS。如果你是Android应用开发人员,那么本篇内容可能不适合你。

集成 GMS 到 Android源码

GMS的获取需要公司和Google达成协议,然后由Google release给公司,无法直接从网上下载。它的目录结构如下

拿到GMS包后需要将它集成进源码,这样编译出来的image文件才能包含了GMS应用。在编译系统的 makefile 中添加下面的语句,
$(call inherit-product, vendor/google/products/gms.mk)
就可以编译到GMS了。至于是选择往哪个makefile中添加,要根据不同公司对编译系统的修改而定,可以尝试在build/core/main.mk中添加。
这里的gms.mk负责总揽GMS的编译,其中的 PRODUCT_PACKAGES
变量列举了哪些 apk 会被编译到,例如
PRODUCT_PACKAGES += \
GoogleBackupTransport \
SetupWizard

就表明 GoogleBackupTransport 和 SetupWizard 会被编译到。然而这里只是指定了apk 的会不会被编译,不同的 apk 编译的条件会不同,真正编译的 makefile 在google/apps 目录里对应 apk 的文件夹下。Google 已经为不同平台(x86/arm 等)设计好了对应的 GMS apk,并且在编译时会识别当前系统所在的平台,自动编译对应的 apk,极大的简化了 GMS 对不同平台的适配过程。
这里还需要注意某些GMS应用是包含lib库的,如果整包升级GMS google 都是将相应的Android.mk文件写好了的,一般集成不会出什么问题,但如果有些需求要单独升级GMS包里面的某个应用,就得小心lib库问题了,lib库有变动,相应的就需要修改编译的Android.mk文件。曾经遇到过一个单独升级LatinImeGoogle 应用问题,拿到新LatinImeGoogle后,adb install 安装后大概测试了下,没什么问题,就直接在代码里用新的LatinImeGoogle替换掉旧的,以为没什么问题,但出完版本后发现LatinImeGoogle一启用就报FC问题,错误log如下:

E/AndroidRuntime(10553): FATAL EXCEPTION: mainE/AndroidRuntime(10553): Process: com.google.android.inputmethod.latin, PID: 10553E/AndroidRuntime(10553): java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/system/app/LatinImeGoogle/LatinImeGoogle.apk"],nativeLibraryDirectories=[/system/app/LatinImeGoogle/lib/arm, /vendor/lib, /system/lib]]] couldn't find "libjni_keyboarddecoder.so"E/AndroidRuntime(10553):  at java.lang.Runtime.loadLibrary(Runtime.java:366)

很明显缺少了libjni_keyboarddecoder.so文件。但为何之前adb install后测试没报出问题呢?原因就在与adb install 安装的应用系统会去解析打包在apk内部的lib库文件,所以没有问题很正常。而预制应用在Android L的版本上系统不会去解析打包在apk内部的lib文件。上面问题产生的原因就在于新的LatinImeGoogle增加了一个libjni_keyboarddecoder.so文件,但Android.mk没有同步修改,导致预制失败。打开LatinImeGoogle下的Android.mk,找到下面这句:

LOCAL_PREBUILT_JNI_LIBS := \    @lib/$(my_src_abi)/libjni_unbundled_latinimegoogle.so

在LOCAL_PREBUILT_JNI_LIBS里追加上缺少的lib库,问题就ok了。

LOCAL_PREBUILT_JNI_LIBS := \    @lib/$(my_src_abi)/libjni_unbundled_latinimegoogle.so \    @lib/$(my_src_abi)/libjni_keyboarddecoder.so

LOCAL_PREBUILT_JNI_LIBS表示apk自身的lib库文件,
“@”标识符会将其抽离出来放置在apk同级目录下的lib文件夹中,并将其从原来的apk文件中删除掉。这点可以从编译log里看出

GMS OVERRIDES && OVERLAY 机制

由于 GMS 包中的某些应用功能与源码中的应用功能相似,所以 Google 设置了OVERRIDES 机制,开启开机制后可以屏蔽掉源码中的某些应用。比如 Hangouts 应用的功能与 Mms 应用类似,在 Hangouts 的 Android.mk 文件中有这样一句:
LOCAL_OVERRIDES_PACKAGES := Mms
这句话的意思就是屏蔽掉 Mms 模块,如果不注释掉这句最终编译生成的镜像文件中将不会包含 Mms 应用。这一点要特别注意在集成完 GMS 后最好在 GMS 包的根目录下是用命令:
grep LOCAL_OVERRIDES_PACKAGES . -nsr –include=*.mk
查看有哪些应用开启了 OVERRIDES 机制,防止需要的应用被 GMS 包中的应用屏蔽掉。与 OVERRIDES 类似的还有 OVERLAY,在google/products/gms_overlay 下包含一些xml 文件,这些文件里定义了一些字串,会替换源码中的同名字串,如果源码中没有该字串,会引起编译错误,这时就需要注释掉该字串。

GMS 覆盖 源码中的 webviewchromium

webviewchromium是WebView的内核,4.4之后的代码位于源码中的external/chromium_org路径下,GMS包中包含了编译好的webviewchromium,如果要使用它,而不是直接由源码编译生成,可以修改gms.mk文件,在其中有如下内容:

# Setting PRODUCT_PREBUILT_WEBVIEWCHROMIUM as yes will prevent from building# webviewchromium from source, and use prebuilt WebViewGoogle.apk in GMS packPRODUCT_PREBUILT_WEBVIEWCHROMIUM := yesifeq ($(PRODUCT_PREBUILT_WEBVIEWCHROMIUM),yes)PRODUCT_PACKAGES += WebViewGoogle# The following framework overlay must be included if prebuilt WebViewGoogle.apk# is usedPRODUCT_PACKAGE_OVERLAYS += vendor/google/apps/WebViewGoogle/overlayendif

将 PRODUCT_PREBUILT_WEBVIEWCHROMIUM 的值设置为 yes 即可覆盖源码中的webviewchromium。
如果要验证覆盖是否成功可以通过检查UserAgent的变化来实现。具体如下:
1.写一个 webview 的 demo,打印其 UserAgent 值。例如:

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    WebView webview = new WebView(this);    webview.layout(0, 0, 0, 0);    WebSettings settings = webview.getSettings();    String ua = settings.getUserAgentString();    Log.d("UserAgent", "UserAgent="+ua);    setContentView(webview);}

2.修 改external/chromium_org/android_webview/common/aw_content_client.cc 文 件中定义 UserAgent 部分的代码 ,例如将其修改成:

std::string GetUserAgent() {    // "Version/4.0" had been hardcoded in the legacy WebView.    std::string product = "Version/3.0 " + GetProduct();    if (CommandLine::ForCurrentProcess()->HasSwitch(    switches::kUseMobileUserAgent)) {        product += " Mobile_TEST";    }    return content::BuildUserAgentFromProduct(product);}

这时打印出 webview 的 Demo 中的 UserAgent,若没有出现” Mobile_TEST”的字段,则表示已经将系统的 webview 内核成功覆盖。

单独升级某个 GMS 应用问题

单独升级 GMS 中的某个应用有风险,如果确实要升级,除了替换掉旧 apk 时,要注意新 apk 的文件结构是否和之前的结构一致。文件有新增,删除,重命名等情况,相应的 Android.mk 文件也要跟着修改.

上图是Velvet应用新旧版本的lib库文件结构对比。如果通过 adb install 命令安装新的 Velvet 应用,进行测试会发现没有什么问题,一切正常。但如果直接替换应用提交代码,download 新版本后发现报 lib 库文件缺失的 FC 问题。这就是由于其中的 lib 库文件名发生了变化,而 make 文件没有同步修改造成的。如下修改能避免该问题:

查看编译生成的GMS应用

不是GMS包中的所有应用都需要预置,如果要查看系统最终预置了哪些GMS应用,可以使用命令adb shell pm list packages查看,由于大部分的GMS应用包名都是com.google.xxx的形式命名的,使用
adb shell pm list packages|grep google
命令可以更加方便的查看。如果要查看GMS 应用包名与 APK 名的对应关系,可以用命令
adb shell pm list packages -f |grep google
输出结果类似如下:

package:/system/app/ConfigUpdater/ConfigUpdater.apk=com.google.android.configupdaterpackage:/system/app/talkback/talkback.apk=com.google.android.marvin.talkbackpackage:/system/app/Gmail2/Gmail2.apk=com.google.android.gmpackage:/system/priv-app/SetupWizard/SetupWizard.apk=com.google.android.setupwizardpackage:/system/app/Music2/Music2.apk=com.google.android.musicpackage:/system/app/CloudPrint/CloudPrint.apk=com.google.android.apps.cloudprint

GMS应用定制修改

GMS的预制并不是简单的将GMS包加入到源码,然后编译生成就完事了,不同的客户肯定对预置的应用有不同的定制需求,聪明的Google也预先考虑到了这点,对GMS中的部分应用提供了定制接口。比如可以定制Chrome的书签和主页,可以定制开机向导的流程,甚至允许往开机向导里面加入自己的页面。
预制只是开始,定制才是噩梦的开端。本篇先到此为止,针对定制GMS会另写一篇。

更多相关文章

  1. Ubuntu11.10 64Bit版上的Android(安卓)4.0 开发环境搭建
  2. Android实现打开系统照相机&相册图片展示
  3. Android(安卓)Device中添加busybox
  4. Android(安卓)建立AIDL的步骤
  5. [Android]自定义组件示例:使用attrs.xml文件定制RadioButton
  6. Android(安卓)ProgressBar 自定义样式(一)
  7. 玩懂Log,打开Android大门(sundy深入浅出)之一
  8. Android生成签名文件并用其对apk文件进行签名(Failure [INSTALL_P
  9. Android知识体系总结之Android部分之Toast篇

随机推荐

  1. php安装amqp扩展(windows)
  2. php+js+ajax实现简单的回帖功能
  3. PHP 闭包之变量作用域
  4. PHP实现笛卡尔积算法
  5. PHP实现支付宝支付的方法
  6. 关于PHP中sqlite3的使用
  7. PHP 生成随机红包算法
  8. 使用phpqrcode生成二维码
  9. php调试利器:FirePHP的安装与使用
  10. PHP Redis相关操作大全