Skip to content

Commit

Permalink
[tinker] Bugfix:
Browse files Browse the repository at this point in the history
    1. On Android 4.2 or newer, Resources in activity lost the configuration we update before it was
created.
    2. On Android N or newer, Resource patch lost its effects when rotate screen at any activity
with webview.
  • Loading branch information
tys282000 committed Jan 5, 2017
1 parent e50c622 commit d0522fb
Show file tree
Hide file tree
Showing 3 changed files with 464 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package com.tencent.tinker.loader;

import android.app.Instrumentation;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;

import com.tencent.tinker.loader.shareutil.ActivityResFixInstrumentation;
import com.tencent.tinker.loader.shareutil.ShareConstants;
import com.tencent.tinker.loader.shareutil.ShareReflectUtil;

Expand Down Expand Up @@ -50,6 +54,9 @@ class TinkerResourcePatcher {
private static Field packagesFiled = null;
private static Field resourcePackagesFiled = null;

private static Field instrumentationField = null;
private static Field publicSourceDirField = null;

public static void isResourceCanPatch(Context context) throws Throwable {
// - Replace mResDir to point to the external resource file instead of the .apk. This is
// used as the asset path for new Resources objects.
Expand Down Expand Up @@ -165,6 +172,20 @@ public static void isResourceCanPatch(Context context) throws Throwable {
resourcesImplFiled = Resources.class.getDeclaredField("mResourcesImpl");
resourcesImplFiled.setAccessible(true);
}

try {
instrumentationField = activityThread.getDeclaredField("mInstrumentation");
instrumentationField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("cannot find 'mInstrumentation' field");
}

try {
publicSourceDirField = ApplicationInfo.class.getDeclaredField("publicSourceDir");
publicSourceDirField.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new IllegalStateException("cannot find 'mInstrumentation' field");
}
}

public static void monkeyPatchExistingResources(Context context, String externalResourceFile) throws Throwable {
Expand Down Expand Up @@ -219,6 +240,23 @@ public static void monkeyPatchExistingResources(Context context, String external
}
}

try {
final Instrumentation origInstrumentation = (Instrumentation) instrumentationField.get(currentActivityThread);
final Instrumentation activityResFixInstrumentation = new ActivityResFixInstrumentation(context, origInstrumentation);
instrumentationField.set(currentActivityThread, activityResFixInstrumentation);
} catch (NoSuchFieldException e) {
// Version below api 17 has no mResources field in ContextThemeWrapper,
// so just ignore this exception. Otherwise we should rethrow it.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
throw e;
}
}

// Handle issues caused by WebView on Android N.
// Issue: On Andorid N, if an activity contains a webview, when screen rotates
// our resource patch may lost effects.
publicSourceDirField.set(context.getApplicationInfo(), externalResourceFile);

if (!checkResUpdate(context)) {
throw new TinkerRuntimeException(ShareConstants.CHECK_RES_INSTALL_FAIL);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Tencent is pleased to support the open source community by making Tinker available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.tencent.tinker.loader.shareutil;

import android.app.Activity;
import android.app.Application;
import android.app.Instrumentation;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.IBinder;
import android.view.ContextThemeWrapper;

import java.lang.reflect.Field;

/**
* Created by tangyinsheng on 2017/1/6.
*/

public class ActivityResFixInstrumentation extends InstrumentationProxy {
private static Field mResourcesField = null;

private final Context mContext;

public ActivityResFixInstrumentation(Context context, Instrumentation base) throws NoSuchFieldException {
super(base);
this.mContext = context;
mResourcesField = ContextThemeWrapper.class.getDeclaredField("mResources");
mResourcesField.setAccessible(true);
}

@Override
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
final Activity result = super.newActivity(cl, className, intent);
replaceResources(result);
return result;
}

@Override
public Activity newActivity(Class<?> clazz, Context context, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, Object lastNonConfigurationInstance) throws InstantiationException, IllegalAccessException {
final Activity result = super.newActivity(clazz, context, token, application, intent, info, title, parent, id, lastNonConfigurationInstance);
replaceResources(result);
return result;
}

private void replaceResources(ContextThemeWrapper component) {
if (component == null) {
return;
}
try {
mResourcesField.set(component, mContext.getApplicationContext().getResources());
} catch (IllegalAccessException e) {
new IllegalStateException("cannot access 'mResources' field of component " + component);
}
}
}
Loading

0 comments on commit d0522fb

Please sign in to comment.