10
10
import java .io .InputStreamReader ;
11
11
import java .io .InvalidClassException ;
12
12
import java .io .OutputStreamWriter ;
13
+ import java .util .ArrayList ;
13
14
import java .util .HashMap ;
14
15
import java .util .HashSet ;
16
+ import java .util .List ;
15
17
import java .util .zip .ZipEntry ;
16
18
import java .util .zip .ZipOutputStream ;
17
19
24
26
import dalvik .system .DexFile ;
25
27
26
28
public class DexFactory {
27
- private static final char CLASS_NAME_LOCATION_SEPARATOR = '_' ;
29
+ private static final String COM_TNS_GEN_PREFIX = "com.tns.gen." ;
28
30
29
31
private final Logger logger ;
30
32
private final File dexDir ;
@@ -61,8 +63,9 @@ public DexFactory(Logger logger, ClassLoader classLoader, File dexBaseDir, Strin
61
63
static long totalMultiDexTime = 0 ;
62
64
static long totalLoadDexTime = 0 ;
63
65
64
- public Class <?> resolveClass (String name , String className , String [] methodOverrides , String [] implementedInterfaces , boolean isInterface ) throws ClassNotFoundException , IOException {
66
+ public Class <?> resolveClass (String baseClassName , String name , String className , String [] methodOverrides , String [] implementedInterfaces , boolean isInterface ) throws ClassNotFoundException , IOException {
65
67
String fullClassName = className .replace ("$" , "_" );
68
+ String originalFullClassName = fullClassName ;
66
69
67
70
// try to get pre-generated binding classes
68
71
try {
@@ -84,19 +87,31 @@ public Class<?> resolveClass(String name, String className, String[] methodOverr
84
87
}
85
88
//
86
89
90
+ // new: com.tns.gen.android.widget.DatePicker_MyActivity_59_56_
91
+ // old: com.tns.tests.Button1_fMyActivity_l56_c44__MyButton
92
+ // ne1: com.tns.tests.Button1_MyActivity_58_44_MyButton_0
87
93
Class <?> existingClass = this .injectedDexClasses .get (fullClassName );
88
94
if (existingClass != null ) {
89
95
return existingClass ;
90
96
}
91
97
92
- String classToProxy = this .getClassToProxyName (className );
93
- String dexFilePath = classToProxy ;
98
+ String classToProxy ;
99
+ if (!baseClassName .isEmpty ()) {
100
+ classToProxy = this .getClassToProxyName (baseClassName );
101
+ } else {
102
+ classToProxy = this .getClassToProxyName (className );
103
+ }
94
104
95
- if (!isInterface ) {
96
- dexFilePath += CLASS_NAME_LOCATION_SEPARATOR + name ;
105
+ // strip the `com.tns.gen` off the base extended class name
106
+ String desiredDexClassName = this .getClassToProxyName (fullClassName );
107
+
108
+ // when interfaces are extended as classes, we still want to preserve
109
+ // just the interface name without the extra file, line, column information
110
+ if (!baseClassName .isEmpty () && isInterface ) {
111
+ fullClassName = COM_TNS_GEN_PREFIX + classToProxy ;
97
112
}
98
113
99
- File dexFile = this .getDexFile (dexFilePath );
114
+ File dexFile = this .getDexFile (desiredDexClassName );
100
115
101
116
// generate dex file
102
117
if (dexFile == null ) {
@@ -105,7 +120,12 @@ public Class<?> resolveClass(String name, String className, String[] methodOverr
105
120
logger .write ("generating proxy in place" );
106
121
}
107
122
108
- dexFilePath = this .generateDex (name , classToProxy , methodOverrides , implementedInterfaces , isInterface );
123
+ String dexFilePath ;
124
+ if (isInterface ) {
125
+ dexFilePath = this .generateDex (name , classToProxy , methodOverrides , implementedInterfaces , isInterface );
126
+ } else {
127
+ dexFilePath = this .generateDex (desiredDexClassName , classToProxy , methodOverrides , implementedInterfaces , isInterface );
128
+ }
109
129
dexFile = new File (dexFilePath );
110
130
long stopGenTime = System .nanoTime ();
111
131
totalGenTime += stopGenTime - startGenTime ;
@@ -145,16 +165,21 @@ public Class<?> resolveClass(String name, String className, String[] methodOverr
145
165
// However, this is the only viable way to get our dynamic classes
146
166
// loaded within the system class loader
147
167
148
- df = DexFile .loadDex (jarFilePath , new File (this .odexDir , fullClassName ).getAbsolutePath (), 0 );
149
- result = df .loadClass (fullClassName , classLoader );
168
+ if (isInterface ) {
169
+ df = DexFile .loadDex (jarFilePath , new File (this .odexDir , fullClassName ).getAbsolutePath (), 0 );
170
+ result = df .loadClass (fullClassName , classLoader );
171
+ } else {
172
+ df = DexFile .loadDex (jarFilePath , new File (this .odexDir , desiredDexClassName ).getAbsolutePath (), 0 );
173
+ result = df .loadClass (desiredDexClassName , classLoader );
174
+ }
150
175
} catch (IOException e ) {
151
176
e .printStackTrace ();
152
177
// fall back to DexClassLoader
153
178
DexClassLoader dexClassLoader = new DexClassLoader (jarFilePath , this .odexDir .getAbsolutePath (), null , classLoader );
154
179
result = dexClassLoader .loadClass (fullClassName );
155
180
}
156
181
157
- this .injectedDexClasses .put (fullClassName , result );
182
+ this .injectedDexClasses .put (originalFullClassName , result );
158
183
159
184
return result ;
160
185
}
@@ -191,11 +216,11 @@ public static String strJoin(String[] array, String separator) {
191
216
private String getClassToProxyName (String className ) throws InvalidClassException {
192
217
String classToProxy = className ;
193
218
194
- if (className .startsWith ("com.tns.gen." )) {
219
+ if (className .startsWith (COM_TNS_GEN_PREFIX )) {
195
220
classToProxy = className .substring (12 );
196
221
}
197
222
198
- if (classToProxy .startsWith ("com.tns.gen." )) {
223
+ if (classToProxy .startsWith (COM_TNS_GEN_PREFIX )) {
199
224
throw new InvalidClassException ("Can't generate proxy of proxy" );
200
225
}
201
226
0 commit comments