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

178 行
7.3 KiB

using UnityEngine;
using System.Reflection;
using System;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using HuaweiService.apm;
namespace HuaweiService
{
[AttributeUsage(AttributeTargets.Method)]
public class AddCustomTrace : Attribute
{
string m_name;
bool m_enable;
public AddCustomTrace(string name, bool enable = true){
m_name = name;
m_enable = enable;
}
public string name{
get{
return m_name;
}
}
public bool enable{
get{
return m_enable;
}
set{
m_enable = value;
}
}
}
public class TraceInjector
{
public static void Inject(string assemblyPath)
{
//Debug.Log("inject custom trace Start");
// 按路径读取程序集, 如果文件不存在则返回错误信息
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)
{
// 找到method中需要注入的类型
var needInjectAttr = typeof(AddCustomTrace).FullName;
bool needInject = method.CustomAttributes.Any(typeAttribute => typeAttribute.AttributeType.FullName == needInjectAttr);
if (!needInject)
{
continue;
}
// 只对公有方法进行注入
if (method.IsConstructor || method.IsGetter || method.IsSetter || !method.IsPublic)
continue;
Inject(module, method, type);
}
}
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)
{
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");
}
//获取方法AddCustomTrace
AddCustomTrace attr = getTraceAttribute(type, method);
//判断功能是否开启
if(attr.enable != true){
//Debug.Log(method.Name + " close add custom trace attribute.");
return;
}
//获取特性名称
String name = attr.name;
//更改待注入函数局部变量表
method.Body.InitLocals = true;
var customTraceType = module.ImportReference(typeof(CustomTrace));
var customTraceTypeDef = new VariableDefinition(customTraceType);
method.Body.Variables.Add(customTraceTypeDef);
//准备注入的函数
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"));
//设置一些标签用于语句跳转
Instruction first = method.Body.Instructions[0];
// 开始注入IL代码
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));
//在每一个返回的地方插入stop函数,注意插入指令之后,method.Body.Instructions.Count会增加,需要调整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;
}
}
}
//获取函数的特性
private static AddCustomTrace getTraceAttribute(TypeDefinition type, MethodDefinition method){
Type inejectClassType = Type.GetType(type.FullName);
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;
}
}
}