由于WebView直接在XML中生成会使得WebView直接强引用了当前Activity的对象,易于引起Activity的leak,故将WebView对象的创建修改为如下:
// 此处应用 Application的Context并自行构造WebView的对象会导致兼容性问题,在部分手机上会出现 实例化问题 java.lang.reflect.InvocionTargetException
private void setContentView() {
LinearLayout rootLinear = (LinearLayout) LayoutInflater.from(getApplicationContext()).inflate(R.layout.layout_no_reload_web, new FrameLayout(getApplicationContext()), false);
progressBar = ButterKnife.findById(rootLinear, R.id.progressBar);
webView = new WebView(getApplicationContext());
rootLinear.addView(webView, new LinearLayout.LayoutParams(-1, -1));
setView(rootLinear);
}
但是这样操作之后,在线上运行之后爆出了大量的.RuntimeException 异常
0. java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jiedai.loan/com.jiedai.loan.ui.activity.WebActivity}: android.util.AndroidRuntimeException: java.lang.reflect.InvocionTargetException
1. android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2793)
2. android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2864)
3. android.app.ActivityThread.-wrap12(ActivityThread.java)
4. android.app.ActivityThread$H.handleMessage(ActivityThread.java:1567)
5. android.os.Handler.dispchMessage(Handler.java:105)
6. android.os.Looper.loop(Looper.java:156)
7. android.app.ActivityThread.main(ActivityThread.java:6523)
8. java.lang.reflect.Method.invoke(Nive Method)
9. com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
10. com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)
经查阅资料,说是WebView的构造器本身存在部分机型的兼容性问题。
开始的时候,猜测是由于上述改动造成的:在此之前从未出现这个报错,但是仅仅是此次修改如上代码之后才出现并且是大量的。
但是在新的版本上线后,将上述代码复原后,仍然会有同样的crash出现,故上述说法不成立,就追着兼容性问题方向qu去探索。
在Stack Overflow上找到同样的问题:
Android NoSuchMethodException: callDrawGLFunction
根据堆栈信息的对应,上述堆栈信息代码不全,全部堆栈信息在结尾处会贴出。
"Api21CompatibilityDelegate means webview believes it's running on 21. Renaming callDrawGLFunction happened after API21, hence webview is trying look for the old name."
上述对应的意思就是,API 21之后的系统做了一个方法的重命名,由callDrawGLFunction改为callDrawGLFunction2,并且针对这个重命名做了低版本的兼容,也就是Api21CompatibilityDelegate这个类用于版本兼容的,当属于低版本时会匹配低版本相对应的方法来处理。
故,在Google官方层面实际上是做了这个的兼容处理的,会出现如此的bug,也是定制化ROM未做兼容处理,导致找寻不到方法。
com.android.webview.chromium.WebViewDelegateFactory$Api21CompatibilityDelegate 兼容源码
查看源码
在实例化内部类Api21CompatibilityDelegate的过程中,通过反射调用了HardwareCanvas的callDrawGLFunction方法,由于此方法在21+的系统中更名为callDrawGLFunction2,导致反射不到此方法,抛出异常。
Api21CompatibilityDelegate() {
try {
// Important: This reflection essentially defines a snapshot of some hidden APIs
// at version 21 of the framework for compatibility reasons, and the reflection
// should not be changed even if those hidden APIs change in future releases.
mIsTagEnabledMethod = Trace.class.getMethod("isTagEnabled", long.class);
mAddChangeCallbackMethod = Class.forName("android.os.SystemProperties")
.getMethod("addChangeCallback", Runnable.class);
mGetViewRootImplMethod = View.class.getMethod("getViewRootImpl");
mInvokeFunctorMethod =
Class.forName("android.view.ViewRootImpl")
.getMethod("invokeFunctor", long.class, boolean.class);
mDetachFunctorMethod = Class.forName("android.view.ViewRootImpl")
.getMethod("detachFunctor", long.class);
//在此处调用callDrawGLFunction方法
mCallDrawGLFunctionMethod = Class.forName("android.view.HardwareCanvas")
.getMethod("callDrawGLFunction", long.class);
mGetAssignedPackageIdentifiersMethod =
AssetManager.class.getMethod("getAssignedPackageIdentifiers");
mAddAssetPathMethod = AssetManager.class.getMethod("addAssetPath", String.class);
mCurrentApplicationMethod =
Class.forName("android.app.ActivityThread").getMethod("currentApplication");
mGetStringMethod = Class.forName("android.net.http.ErrorStrings")
.getMethod("getString", int.class, Context.class);
mGetLoadedPackageInfoMethod = Class.forName("android.webkit.WebViewFactory")
.getMethod("getLoadedPackageInfo");
} catch (Exception e) {
throw new RuntimeException("Invalid reflection", e);
}
}
android.view.HardwareCanvas
在这里我们可以明显看到HardwareCanvas的源码中只有callDrawGLFunction2方法
/**
* Hardware accelerated canvas.
*
* @hide
*/
public abstract class HardwareCanvas extends Canvas {
...
/**
* Calls the function specified with the drawGLFunction function pointer. This is
* functionality used by webkit for calling into their renderer from our display lists.
* This function may return true if an invalidation is needed after the call.
*
* @param drawGLFunction A native function pointer
*
* @return {@link RenderNode#STATUS_DONE}
*
* @hide
*/
public abstract int callDrawGLFunction2(long drawGLFunction);
...
}
com.android.webview.chromium.WebViewDelegateFactory
通过 WebViewDelegateFactory 的静态方法来实例化 其内部类 Api21CompatibilityDelegate
/**
* Creates a {@link WebViewDelegate com.android.webview.chromium.WebViewDelegate} compatible
* with the API 21 version of the framework in which
* {@link android.webkit.WebViewDelegate android.webkit.WebViewDelegate} had not yet been
* introduced.
*
* @return the created delegate
*/
static WebViewDelegate createApi21CompatibilityDelegate() {
return new Api21CompatibilityDelegate();
}
com.android.webview.chromium.WebViewChromiumFactoryProvider
在构造方法中调用了上一步的方法,来实例化Api21CompatibilityDelegate;
并且从注释中可以看出,下面两个构造方法分别用于不同系统下(21作为分界线)进行实例化
/**
* Constructor called by the API 21 version of {@link WebViewFactory} and earlier.
*/
public WebViewChromiumFactoryProvider() {
initialize(WebViewDelegateFactory.createApi21CompatibilityDelegate());
}
/**
* Constructor called by the API 22 version of {@link WebViewFactory} and later.
*/
public WebViewChromiumFactoryProvider(android.webkit.WebViewDelegate delegate) {
initialize(WebViewDelegateFactory.createProxyDelegate(delegate));
}
android.webkit.WebViewFactory
在getProviderClass()中通过反射的方式实现了对WebViewChromiumFactoryProvider的实例化,然后对外开放包权限的静态方法getProvider()方法供WebView调用。
/**
* Top level factory, used creating all the main WebView implementation classes.
*
* @hide
*/
@SystemApi
public final class WebViewFactory {
private static final String CHROMIUM_WEBVIEW_FACTORY =
"com.android.webview.chromium.WebViewChromiumFactoryProvider";
private static Class<WebViewFactoryProvider> getProviderClass() {
Context webViewContext = null;
Application initialApplication = AppGlobals.getInitialApplication();
try {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
"WebViewFactory.getWebViewContextAndSetProvider()");
try {
webViewContext = getWebViewContextAndSetProvider();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
initialApplication.getAssets().addAssetPathAsSharedLibrary(
webViewContext.getApplicationInfo().sourceDir);
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
loadNativeLibrary(clazzLoader);
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
try {
//在此处通过反射获取WebViewChromiumFactoryProvider的Class实例
return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
true, clazzLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading provider", e);
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (MissingWebViewPackageException e) {
// If the package doesn't exist, then try loading the null WebView instead.
// If that succeeds, then this is a device without WebView support; if it fails then
// swallow the failure, complain that the real WebView is missing and rethrow the
// original exception.
try {
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
} catch (ClassNotFoundException e2) {
// Ignore.
}
Log.e(LOGTAG, "Chromium WebView package does not exist", e);
throw new AndroidRuntimeException(e);
}
}
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
// us honest and minimize usage of WebView internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
final int uid = Process.myUid();
if (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID) {
throw new UnsupportedOperationException(
"For security reasons, WebView is not allowed in privileged processes");
}
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
//在此处调用了getProviderClass()方法
Class<WebViewFactoryProvider> providerClass = getProviderClass();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
try {
//在此处将WebViewFactoryProvider最终实例化出来,21+的通过此构造方法实例化,,21及以下通过无参的构造实例化
sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
.newInstance(new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
Log.e(LOGTAG, "error instantiating provider", e);
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
StrictMode.setThreadPolicy(oldPolicy);
}
}
}
}
其中 getProvider() 在不同系统下 通过不同的 WebViewFactoryProvider的构造器进行实例化
上文代码中是通过有参构造实例化WebViewFactoryProvider,在API 21 以上的版本;
下文代码中是通过无参构造实例化WebViewFactoryProvider,在API 21 及以下的版本。
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
// us honest and minimize usage of WebView internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
loadNativeLibrary();
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Class<WebViewFactoryProvider> providerClass;
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getFactoryClass()");
try {
providerClass = getFactoryClass();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading provider", e);
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
try {
sProviderInstance = providerClass.newInstance();
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
Log.e(LOGTAG, "error instantiating provider", e);
throw new AndroidRuntimeException(e);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
StrictMode.setThreadPolicy(oldPolicy);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
}
}
android.webkit.WebView
在WebView的源码中可以看到一些未被开放到SDK的方法,其中,WebView的隐藏构造器,其余构造器都是通过此构造方法来实例化WebView,那么在此方法中就调用 ensureProviderCreated(),而 ensureProviderCreated 中就调用了 WebViewFactory 的getFactory()方法
@Widget
public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
/**
* WebView隐藏构造器,其余构造器都是通过此构造方法来实例化WebView,那么在此方法中就调用ensureProviderCreated()
* @hide
*/
@SuppressWarnings("deprecation") // for super() call into deprecated base class constructor.
protected WebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes,
Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) {
super(context, attrs, defStyleAttr, defStyleRes);
if (context == null) {
throw new IllegalArgumentException("Invalid context argument");
}
sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >=
Build.VERSION_CODES.JELLY_BEAN_MR2;
checkThread();
ensureProviderCreated();
mProvider.init(javaScriptInterfaces, privateBrowsing);
// Post condition of creating a webview is the CookieSyncManager.getInstance() is allowed.
CookieSyncManager.setGetInstanceIsAllowed();
}
private void ensureProviderCreated() {
checkThread();
if (mProvider == null) {
// As this can get called during the base class constructor chain, pass the minimum
// number of dependencies here; the rest are deferred to init().
//在此处调用WebViewFactory的getFactory()方法
mProvider = getFactory().createWebView(this, new PrivateAccess());
}
}
}
那么到了这里就可以看到整个源码的执行逻辑了。在WebView的整个代理工厂的逻辑中,通过 Api21CompatibilityDelegate 来做21及以下版本的方法兼容,21+ 的正常调用更名后的 callDrawGLFunction2()方法,而低版本的会通过反射来调用方法 callDrawGLFunction()。并且在 Api21CompatibilityDelegate 的兼容逻辑中做了异常处理逻辑,出现反射异常时会抛出 new RuntimeException("Invalid reflection", e)。而这一系列的逻辑又都是在WebView的实例化的过程就会执行。
其实,由上述的一系列逻辑中,我们可以看到实际上Google官方对针对 callDrawGLFunction 的更名做了低版本的兼容处理的
那么问题如何出现的呢?也很显然的,系统ROM做定制化处理时导致官方的这套逻辑在运行时出现了额外的异常case,如定制ROM将21-的callDrawGLFunction方法直接给更名了 callDrawGLFunction2 那么在运行到 低版本兼容逻辑时 就会自动寻找 callDrawGLFunction() ,然后找不到并抛出异常
故,此异常的出现 并非Goggle官方的bug,而是手机厂商ROM的bug。
crash堆栈信息
05-18 15:23:51.738 22422-22422/com.example.abdulmoeed.webviewtest E/WebViewFactory﹕ error instantiating provider
java.lang.RuntimeException: Invalid reflection
at com.android.webview.chromium.WebViewDelegateFactory$Api21CompatibilityDelegate.<init>(WebViewDelegateFactory.java:223)
at com.android.webview.chromium.WebViewDelegateFactory.createApi21CompatibilityDelegate(WebViewDelegateFactory.java:97)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(WebViewChromiumFactoryProvider.java:97)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1606)
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:124)
at android.webkit.WebView.getFactory(WebView.java:2194)
at android.webkit.WebView.ensureProviderCreated(WebView.java:2189)
at android.webkit.WebView.setOverScrollMode(WebView.java:2248)
at android.view.View.<init>(View.java:3588)
at android.view.View.<init>(View.java:3682)
at android.view.ViewGroup.<init>(ViewGroup.java:497)
at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:55)
at android.webkit.WebView.<init>(WebView.java:544)
at android.webkit.WebView.<init>(WebView.java:489)
at android.webkit.WebView.<init>(WebView.java:472)
at android.webkit.WebView.<init>(WebView.java:459)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
at android.view.LayoutInflater.createView(LayoutInflater.java:607)
at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55)
at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:684)
at android.view.LayoutInflater.inflate(Unknown Source)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:240)
at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
at com.example.abdulmoeed.webviewtest.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117)
Caused by: java.lang.NoSuchMethodException: callDrawGLFunction [long]
at java.lang.Class.getMethod(Class.java:664)
at java.lang.Class.getMethod(Class.java:643)
at com.android.webview.chromium.WebViewDelegateFactory$Api21CompatibilityDelegate.<init>(WebViewDelegateFactory.java:211)
at com.android.webview.chromium.WebViewDelegateFactory.createApi21CompatibilityDelegate(WebViewDelegateFactory.java:97)
at com.android.webview.chromium.WebViewChromiumFactoryProvider.<init>(WebViewChromiumFactoryProvider.java:97)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.Class.newInstance(Class.java:1606)
at android.webkit.WebViewFactory.getProvider(WebViewFactory.java:124)
at android.webkit.WebView.getFactory(WebView.java:2194)
at android.webkit.WebView.ensureProviderCreated(WebView.java:2189)
at android.webkit.WebView.setOverScrollMode(WebView.java:2248)
at android.view.View.<init>(View.java:3588)
at android.view.View.<init>(View.java:3682)
at android.view.ViewGroup.<init>(ViewGroup.java:497)
at android.widget.AbsoluteLayout.<init>(AbsoluteLayout.java:55)
at android.webkit.WebView.<init>(WebView.java:544)
at android.webkit.WebView.<init>(WebView.java:489)
at android.webkit.WebView.<init>(WebView.java:472)
at android.webkit.WebView.<init>(WebView.java:459)
at java.lang.reflect.Constructor.newInstance(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:288)
at android.view.LayoutInflater.createView(LayoutInflater.java:607)
at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:55)
at android.view.LayoutInflater.onCreateView(LayoutInflater.java:682)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:741)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at de.robv.android.xposed.XposedBridge.invokeOriginalMethodNative(Native Method)
at de.robv.android.xposed.XposedBridge.handleHookedMethod(XposedBridge.java:684)
at android.view.LayoutInflater.inflate(Unknown Source)
at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:240)
at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102)
at com.example.abdulmoeed.webviewtest.MainActivity.onCreate(MainActivity.java:14)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:117)
方案处理(有待验证)
经过上述分析,定位了属于ROM的Chrome模块出现问题。并对照网上处理方案,属于Android System WebView的兼容问题。也就是厂商系统升级或者单独针对System WebView升级了,由于并未做CPU arm64架构下的兼容处理,导致APP在arm64架构下运行WebView底层的so文件时,出现兼容问题并发生Crash。由此解决方案就是针对APP手动配置其支持的CPU架构。
ndk {
//为了处理Chrome的bug:在arm64 cpu架构下的Android System WebView Crash的问题,去除64位的ABIS的so文件(注意:如此会导致64位下的优化无法作用,会影响部分性能以及兼容性隐患)
abiFilters 'armeabi', 'armeabi-v7a', 'x86', 'mips'//, 'mips64','arm64-v8a', 'x86_64'
}
这样APP就手动指定了能够的适配的CPU架构。那么,未指定的CPU架构还支持么?既然是Crash的处理方案,肯定是让这部分用户可以使用的。64位架构的也是可以运行32位so文件的,也就是说因为原属于64位的so文件存在问题,故抛弃其专属的so文件,让其运行能够兼容的32位的so文件。缺点就是,会导致64位架构做的相应的性能优化以及兼容处理丢失掉。
网友评论