Downloadable Fonts异常求助:非FontCallback方案适配需求(minSdk16)
针对Downloadable Fonts调用ResourcesCompat抛异常的解决方案(minSdk16、禁用v27 FontCallback)
我之前也踩过Downloadable Fonts的类似坑,结合你的限制条件,给你几个针对性的排查和解决方向:
1. 先排查字体XML配置的正确性
这是最容易出错的环节,尤其是无GMS设备也会报错,大概率配置有问题:
- 检查
res/font/下的字体配置XML,确保<font-family>中的属性完全正确:app:fontProviderAuthority:如果用Google Fonts,必须是com.google.android.gms.fonts;自定义provider则要对应你的授权值。app:fontProviderQuery:字体名称必须和Google Fonts上的完全一致(注意大小写、空格,比如"Roboto Slab"不能写成"RobotoSlab")。app:fontProviderCerts:这个是证书验证关键,无GMS设备报错很大概率是证书哈希配置错误。如果是测试阶段,可以暂时移除这个属性(不推荐正式环境),看看是否还抛异常;正式环境必须配置正确的证书数组。
- 别忘了添加本地 fallback 字体:在XML里加
<font>标签指定本地字体文件,这样下载失败时会自动 fallback,避免异常:<font-family xmlns:app="http://schemas.android.com/apk/res-auto"> <!-- 远程字体配置 --> <app:fontProviderAuthority="com.google.android.gms.fonts" app:fontProviderPackage="com.google.android.gms" app:fontProviderQuery="Roboto" app:fontProviderCerts="@array/com_google_android_gms_fonts_certs"/> <!-- 本地 fallback 字体 --> <font app:fontStyle="normal" app:fontWeight="400" app:font="@font/roboto_regular"/> </font-family>
2. 替换同步调用为异步处理(避开v27 FontCallback)
你不能用v27的ResourcesCompat.FontCallback,可以改用v4 support库的FontsContract.FontRequestCallback,这是v24+ support库就有的API,兼容minSdk16:
- 示例代码:
这种方式不会因为同步等待下载而抛出异常,完全避开了v27的API限制。// 构建FontRequest FontRequest fontRequest = new FontRequest( "com.google.android.gms.fonts", "com.google.android.gms", "Roboto", // 要下载的字体名称 R.array.com_google_android_gms_fonts_certs // 证书数组 ); // 自定义回调处理结果 FontsContract.FontRequestCallback fontCallback = new FontsContract.FontRequestCallback() { @Override public void onTypefaceRetrieved(Typeface typeface) { // 成功获取字体,在这里设置到TextView或其他控件 textView.setTypeface(typeface); } @Override public void onTypefaceRequestFailed(int reason) { // 下载失败,使用本地 fallback 字体 textView.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/roboto_regular.ttf")); } }; // 发起异步请求 FontsContract.requestFont( getApplicationContext(), fontRequest, fontCallback, HandlerCompat.createAsync(Looper.getMainLooper()) // 确保回调在主线程执行 );
3. 处理无GMS设备的特殊情况
无GMS设备无法访问Google Fonts的provider,所以必须做兼容:
- 在代码中判断设备是否有GMS服务,没有的话直接加载本地字体:
private boolean hasGooglePlayServices(Context context) { GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance(); int resultCode = apiAvailability.isGooglePlayServicesAvailable(context); return resultCode == ConnectionResult.SUCCESS; } // 使用时 if (hasGooglePlayServices(this)) { // 发起远程字体请求 requestRemoteFont(); } else { // 直接加载本地字体 textView.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/roboto_regular.ttf")); }
4. 确认support库版本兼容性
确保你的support-compat库版本在v24.0.0到v26.1.0之间(符合minSdk16要求,同时避开v27),在build.gradle中配置:
implementation 'com.android.support:support-compat:26.1.0'
最后排查异常栈信息
如果以上步骤都没解决,一定要看具体的异常栈:
- 要是
Resources$NotFoundException:大概率是字体XML的provider属性写错了,或者本地 fallback 字体不存在。 - 要是
SecurityException:肯定是证书配置错误,检查证书数组里的哈希值是否正确。
内容的提问来源于stack exchange,提问作者KolinLoures
相关产品推荐
相关产品推荐

