@@ -42,6 +42,12 @@ public class GenerateJavaStubs : AndroidTask
42
42
[ Required ]
43
43
public string [ ] SupportedAbis { get ; set ; }
44
44
45
+ [ Required ]
46
+ public string TypemapOutputDirectory { get ; set ; }
47
+
48
+ [ Required ]
49
+ public bool GenerateNativeAssembly { get ; set ; }
50
+
45
51
public string ManifestTemplate { get ; set ; }
46
52
public string [ ] MergedManifestDocuments { get ; set ; }
47
53
@@ -71,6 +77,9 @@ public class GenerateJavaStubs : AndroidTask
71
77
72
78
public string ApplicationJavaClass { get ; set ; }
73
79
80
+ [ Output ]
81
+ public string [ ] GeneratedBinaryTypeMaps { get ; set ; }
82
+
74
83
internal const string AndroidSkipJavaStubGeneration = "AndroidSkipJavaStubGeneration" ;
75
84
76
85
public override bool RunTask ( )
@@ -108,71 +117,97 @@ void Run (DirectoryAssemblyResolver res)
108
117
}
109
118
110
119
// Put every assembly we'll need in the resolver
120
+ bool hasExportReference = false ;
121
+ bool haveMonoAndroid = false ;
122
+ var allTypemapAssemblies = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
123
+ var userAssemblies = new Dictionary < string , string > ( StringComparer . OrdinalIgnoreCase ) ;
111
124
foreach ( var assembly in ResolvedAssemblies ) {
112
- if ( bool . TryParse ( assembly . GetMetadata ( AndroidSkipJavaStubGeneration ) , out bool value ) && value ) {
125
+ bool value ;
126
+ if ( bool . TryParse ( assembly . GetMetadata ( AndroidSkipJavaStubGeneration ) , out value ) && value ) {
113
127
Log . LogDebugMessage ( $ "Skipping Java Stub Generation for { assembly . ItemSpec } ") ;
114
128
continue ;
115
129
}
130
+
131
+ bool addAssembly = false ;
132
+ string fileName = Path . GetFileName ( assembly . ItemSpec ) ;
133
+ if ( ! hasExportReference && String . Compare ( "Mono.Android.Export.dll" , fileName , StringComparison . OrdinalIgnoreCase ) == 0 ) {
134
+ hasExportReference = true ;
135
+ addAssembly = true ;
136
+ } else if ( ! haveMonoAndroid && String . Compare ( "Mono.Android.dll" , fileName , StringComparison . OrdinalIgnoreCase ) == 0 ) {
137
+ haveMonoAndroid = true ;
138
+ addAssembly = true ;
139
+ } else if ( MonoAndroidHelper . FrameworkAssembliesToTreatAsUserAssemblies . Contains ( fileName ) ) {
140
+ if ( ! bool . TryParse ( assembly . GetMetadata ( AndroidSkipJavaStubGeneration ) , out value ) || ! value ) {
141
+ string name = Path . GetFileNameWithoutExtension ( fileName ) ;
142
+ if ( ! userAssemblies . ContainsKey ( name ) )
143
+ userAssemblies . Add ( name , assembly . ItemSpec ) ;
144
+ addAssembly = true ;
145
+ }
146
+ }
147
+
148
+ if ( addAssembly ) {
149
+ if ( ! allTypemapAssemblies . Contains ( assembly . ItemSpec ) )
150
+ allTypemapAssemblies . Add ( assembly . ItemSpec ) ;
151
+ }
152
+
116
153
res . Load ( assembly . ItemSpec ) ;
117
154
}
118
155
119
- // However we only want to look for JLO types in user code
120
- List < string > assemblies = new List < string > ( ) ;
156
+ // However we only want to look for JLO types in user code for Java stub code generation
121
157
foreach ( var asm in ResolvedUserAssemblies ) {
122
158
if ( bool . TryParse ( asm . GetMetadata ( AndroidSkipJavaStubGeneration ) , out bool value ) && value ) {
123
159
Log . LogDebugMessage ( $ "Skipping Java Stub Generation for { asm . ItemSpec } ") ;
124
160
continue ;
125
161
}
126
- if ( ! assemblies . All ( x => Path . GetFileName ( x ) != Path . GetFileName ( asm . ItemSpec ) ) )
127
- continue ;
128
- Log . LogDebugMessage ( $ "Adding { asm . ItemSpec } to assemblies.") ;
129
- assemblies . Add ( asm . ItemSpec ) ;
130
- }
131
- foreach ( var asm in MonoAndroidHelper . GetFrameworkAssembliesToTreatAsUserAssemblies ( ResolvedAssemblies ) ) {
132
- if ( bool . TryParse ( asm . GetMetadata ( AndroidSkipJavaStubGeneration ) , out bool value ) && value ) {
133
- Log . LogDebugMessage ( $ "Skipping Java Stub Generation for { asm . ItemSpec } ") ;
134
- continue ;
135
- }
136
- if ( ! assemblies . All ( x => Path . GetFileName ( x ) != Path . GetFileName ( asm . ItemSpec ) ) )
137
- continue ;
138
- Log . LogDebugMessage ( $ "Adding { asm . ItemSpec } to assemblies.") ;
139
- assemblies . Add ( asm . ItemSpec ) ;
162
+ if ( ! allTypemapAssemblies . Contains ( asm . ItemSpec ) )
163
+ allTypemapAssemblies . Add ( asm . ItemSpec ) ;
164
+ userAssemblies . Add ( Path . GetFileNameWithoutExtension ( asm . ItemSpec ) , asm . ItemSpec ) ;
140
165
}
141
166
142
167
// Step 1 - Find all the JLO types
143
168
var scanner = new JavaTypeScanner ( this . CreateTaskLogger ( ) ) {
144
169
ErrorOnCustomJavaObject = ErrorOnCustomJavaObject ,
145
170
} ;
146
- var all_java_types = scanner . GetJavaTypes ( assemblies , res ) ;
147
171
148
- var java_types = all_java_types
149
- . Where ( t => ! JavaTypeScanner . ShouldSkipJavaCallableWrapperGeneration ( t ) )
150
- . ToArray ( ) ;
172
+ List < TypeDefinition > allJavaTypes = scanner . GetJavaTypes ( allTypemapAssemblies , res ) ;
151
173
152
- // Step 2 - Generate Java stub code
174
+ // Step 2 - Generate type maps
175
+ // Type mappings need to use all the assemblies, always.
176
+ WriteTypeMappings ( res , allJavaTypes ) ;
177
+
178
+ var javaTypes = new List < TypeDefinition > ( ) ;
179
+ foreach ( TypeDefinition td in allJavaTypes ) {
180
+ if ( ! userAssemblies . ContainsKey ( td . Module . Assembly . Name . Name ) || JavaTypeScanner . ShouldSkipJavaCallableWrapperGeneration ( td ) ) {
181
+ continue ;
182
+ }
183
+
184
+ javaTypes . Add ( td ) ;
185
+ }
186
+
187
+ // Step 3 - Generate Java stub code
153
188
var success = Generator . CreateJavaSources (
154
189
Log ,
155
- java_types ,
190
+ javaTypes ,
156
191
Path . Combine ( OutputDirectory , "src" ) ,
157
192
ApplicationJavaClass ,
158
193
AndroidSdkPlatform ,
159
194
UseSharedRuntime ,
160
195
int . Parse ( AndroidSdkPlatform ) <= 10 ,
161
- ResolvedAssemblies . Any ( assembly => Path . GetFileName ( assembly . ItemSpec ) == "Mono.Android.Export.dll" ) ) ;
196
+ hasExportReference ) ;
162
197
if ( ! success )
163
198
return ;
164
199
165
200
// We need to save a map of .NET type -> ACW type for resource file fixups
166
- var managed = new Dictionary < string , TypeDefinition > ( java_types . Length , StringComparer . Ordinal ) ;
167
- var java = new Dictionary < string , TypeDefinition > ( java_types . Length , StringComparer . Ordinal ) ;
201
+ var managed = new Dictionary < string , TypeDefinition > ( javaTypes . Count , StringComparer . Ordinal ) ;
202
+ var java = new Dictionary < string , TypeDefinition > ( javaTypes . Count , StringComparer . Ordinal ) ;
168
203
169
204
var managedConflicts = new Dictionary < string , List < string > > ( 0 , StringComparer . Ordinal ) ;
170
205
var javaConflicts = new Dictionary < string , List < string > > ( 0 , StringComparer . Ordinal ) ;
171
206
172
207
// Allocate a MemoryStream with a reasonable guess at its capacity
173
- using ( var stream = new MemoryStream ( java_types . Length * 32 ) )
208
+ using ( var stream = new MemoryStream ( javaTypes . Count * 32 ) )
174
209
using ( var acw_map = new StreamWriter ( stream ) ) {
175
- foreach ( var type in java_types ) {
210
+ foreach ( TypeDefinition type in javaTypes ) {
176
211
string managedKey = type . FullName . Replace ( '/' , '.' ) ;
177
212
string javaKey = JavaNativeTypeManager . ToJniName ( type ) . Replace ( '/' , '.' ) ;
178
213
@@ -237,7 +272,7 @@ void Run (DirectoryAssemblyResolver res)
237
272
manifest . PackageName = PackageName ;
238
273
manifest . ApplicationName = ApplicationName ?? PackageName ;
239
274
manifest . Placeholders = ManifestPlaceholders ;
240
- manifest . Assemblies . AddRange ( assemblies ) ;
275
+ manifest . Assemblies . AddRange ( userAssemblies . Values ) ;
241
276
manifest . Resolver = res ;
242
277
manifest . SdkDir = AndroidSdkDir ;
243
278
manifest . SdkVersion = AndroidSdkPlatform ;
@@ -246,7 +281,7 @@ void Run (DirectoryAssemblyResolver res)
246
281
manifest . NeedsInternet = NeedsInternet ;
247
282
manifest . InstantRunEnabled = InstantRunEnabled ;
248
283
249
- var additionalProviders = manifest . Merge ( Log , all_java_types , ApplicationJavaClass , EmbedAssemblies , BundledWearApplicationName , MergedManifestDocuments ) ;
284
+ var additionalProviders = manifest . Merge ( Log , allJavaTypes , ApplicationJavaClass , EmbedAssemblies , BundledWearApplicationName , MergedManifestDocuments ) ;
250
285
251
286
using ( var stream = new MemoryStream ( ) ) {
252
287
manifest . Save ( Log , stream ) ;
@@ -268,7 +303,7 @@ void Run (DirectoryAssemblyResolver res)
268
303
// Create additional application java sources.
269
304
StringWriter regCallsWriter = new StringWriter ( ) ;
270
305
regCallsWriter . WriteLine ( "\t \t // Application and Instrumentation ACWs must be registered first." ) ;
271
- foreach ( var type in java_types ) {
306
+ foreach ( var type in javaTypes ) {
272
307
if ( JavaNativeTypeManager . IsApplication ( type ) || JavaNativeTypeManager . IsInstrumentation ( type ) ) {
273
308
string javaKey = JavaNativeTypeManager . ToJniName ( type ) . Replace ( '/' , '.' ) ;
274
309
regCallsWriter . WriteLine ( "\t \t mono.android.Runtime.register (\" {0}\" , {1}.class, {1}.__md_methods);" ,
@@ -296,5 +331,13 @@ void SaveResource (string resource, string filename, string destDir, Func<string
296
331
template = applyTemplate ( template ) ;
297
332
MonoAndroidHelper . CopyIfStringChanged ( template , Path . Combine ( destDir , filename ) ) ;
298
333
}
334
+
335
+ void WriteTypeMappings ( DirectoryAssemblyResolver resolver , List < TypeDefinition > types )
336
+ {
337
+ var tmg = new TypeMapGenerator ( ( string message ) => Log . LogDebugMessage ( message ) , SupportedAbis ) ;
338
+ if ( ! tmg . Generate ( types , TypemapOutputDirectory , GenerateNativeAssembly ) )
339
+ throw new XamarinAndroidException ( 99999 , "Failed to generate type maps" ) ;
340
+ GeneratedBinaryTypeMaps = tmg . GeneratedBinaryTypeMaps . ToArray ( ) ;
341
+ }
299
342
}
300
343
}
0 commit comments