本演示项目在Unity for Android Build中启用部分华为HMS和AGC服务,对应的类和函数的名称和用法相同。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

168 行
7.4 KiB

using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;
using System.Reflection;
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using HuaweiService.apm;
namespace HuaweiService{
[InitializeOnLoad]
public class TraceInjectPostProecess{
static TraceInjectPostProecess(){
CompilationPipeline.assemblyCompilationFinished += onFinished;
}
private static void onFinished(string arg1, CompilerMessage[] arg2){
TraceInjector.Inject(arg1);
}
}
public class TraceInjector
{
public static void Inject(string assemblyPath)
{
//Debug.Log("inject custom trace Start");
//Read the assembly according to the path, if the file does not exist, return an error message
if(!System.IO.File.Exists(assemblyPath)){
Debug.LogError(string.Format("{0} is not Exists",
assemblyPath));
}
var readerParameters = new ReaderParameters { ReadSymbols = true };
var assembly = AssemblyDefinition.ReadAssembly(assemblyPath, readerParameters);
if (assembly == null)
{
Debug.LogError(string.Format("InjectTool Inject Load assembly failed: {0}",
assemblyPath));
return;
}
try
{
var module = assembly.MainModule;
foreach (var type in module.Types)
{
foreach (var method in type.Methods)
{
//Find the type that needs to be injected in the method
var needInjectAttr = typeof(AddCustomTrace).FullName;
bool needInject = method.CustomAttributes.Any(typeAttribute => typeAttribute.AttributeType.FullName == needInjectAttr);
if (!needInject)
{
continue;
}
//Only public methods need to be injected
if (method.IsConstructor || method.IsGetter || method.IsSetter || !method.IsPublic)
continue;
Inject(module, method, type, assembly);
}
}
assembly.Write(assemblyPath, new WriterParameters { WriteSymbols = true });
}
catch (System.Exception ex)
{
Debug.LogError(string.Format("InjectTool Inject failed: {0}", ex));
throw;
}
finally
{
if (assembly.MainModule.SymbolReader != null)
{
assembly.MainModule.SymbolReader.Dispose();
}
}
}
private static void Inject(ModuleDefinition module, MethodDefinition method, TypeDefinition type, AssemblyDefinition assembly)
{
if(module == null){
throw new ArgumentNullException("input argument invalid, module is null");
}
if(method == null){
throw new ArgumentNullException("input argument invalid, method is null");
}
if(type == null){
throw new ArgumentNullException("input argument invalid, type is null");
}
//get AddCustomTrace attribute in method
AddCustomTrace attr = getTraceAttribute(type, method, assembly);
//whether the function is turned on
if(attr.enable != true){
return;
}
//get name of attribute
String name = attr.name;
//Change the local variable table of the function to be injected
method.Body.InitLocals = true;
var customTraceType = module.ImportReference(typeof(CustomTrace));
var customTraceTypeDef = new VariableDefinition(customTraceType);
method.Body.Variables.Add(customTraceTypeDef);
//Prepare functions to be injected
MethodReference getInstance = module.ImportReference(typeof(APMS).GetMethod("getInstance"));
MethodReference createInstance = module.ImportReference(typeof(APMS).GetMethod("createCustomTrace", new Type[] {typeof(string)}));
MethodReference customTraceStart = module.ImportReference(typeof(CustomTrace).GetMethod("start"));
MethodReference customTraceEnd = module.ImportReference(typeof(CustomTrace).GetMethod("stop"));
//Set some labels for statement jump
Instruction first = method.Body.Instructions[0];
// start injecting IL code
var ilProcessor = method.Body.GetILProcessor();
ilProcessor.InsertBefore(first, ilProcessor.Create(OpCodes.Nop));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Call, getInstance));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldstr, name));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Callvirt, createInstance));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Stloc, customTraceTypeDef));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Ldloc, customTraceTypeDef));
ilProcessor.InsertBefore(first, Instruction.Create(OpCodes.Callvirt, customTraceStart));
ilProcessor.InsertBefore(first, ilProcessor.Create(OpCodes.Nop));
//Insert stop functions at every return. Note that after inserting the instruction,
//method.Body.Instructions.Count increment,and need to adjust the value of i
for(int i=0;i<method.Body.Instructions.Count;i++){
Instruction ins = method.Body.Instructions[i];
OpCode code = ins.OpCode;
if(ins.OpCode.Equals(OpCodes.Ret) || ins.OpCode.Equals(OpCodes.Throw)){
//Debug.Log("method: " + method.Name + "i: " + i + " code: " + code);
ilProcessor.InsertBefore(ins, ilProcessor.Create(OpCodes.Nop));
ilProcessor.InsertBefore(ins, Instruction.Create(OpCodes.Ldloc, customTraceTypeDef));
ilProcessor.InsertBefore(ins, Instruction.Create(OpCodes.Callvirt, customTraceEnd));
ilProcessor.InsertBefore(ins, ilProcessor.Create(OpCodes.Nop));
i+=4;
}
}
}
//get attribute of given method
private static AddCustomTrace getTraceAttribute(TypeDefinition type, MethodDefinition method, AssemblyDefinition assembly){
Type inejectClassType = Type.GetType(type.FullName + ", " + assembly.Name);
if(inejectClassType == null){
throw new NullReferenceException("Class Type is null, Attribute: " + type.FullName);
}
MethodInfo methodinfo = inejectClassType.GetMethod(method.Name);
if(methodinfo == null){
throw new NullReferenceException("methodinfo in class " + type.FullName + " is null, method name: " + method.Name);
}
AddCustomTrace attr = (AddCustomTrace)methodinfo.GetCustomAttributes(typeof(AddCustomTrace), true)[0] ;
if(attr == null){
throw new NullReferenceException("attr AddCustomTrace on method "+ method.Name + " is null");
}
return attr;
}
}
}