is there a way to get some kind of info or warning, when any Button component has a missing method?
What I mean by that is that when you implement a method for a Button, assign that method in the scene and then e.g. rename the method, the rename won't update the method call in the scene and so it says "< Missing ScriptName.OldMethodName >".
When this happens I'd like to get notified about that - at least when pressing play, or at the very least when deploying the application.
Scott's answer is very close to what you are doing and led to this answer. Although it is missing so many things. You need to do more work to get that script working.
1.You need to get all the Buttons in the scene (including inactive/disabled ones) with Resources.FindObjectsOfTypeAll
.
2.Loop through the buttons and check if the class/script that holds that function exist with reflection. You do this because sometimes, we rename scripts. This could cause problems. Show message of the script does not exist.
You can do this by simply checking if Type.GetType(className);
is null
.
If it is null
then don't even both the test below because the component that holds that Button
's onClick
function has been re-named. Display an error message that says that this script has been deleted or re-named.
3.If the class exist, now check if the function exist with reflection in that class
that is registered to the Button's onClick
event.
This can be done by simply checking if type.GetMethod(functionName);
is null
.
If the function exist, that Button is fine. You don't have to show a message if the function exist. Stop here.
If that returns null
then continue to #4.
4.Check if the function exist, but this time, check if the function is declared with a private
access modifier.
This is a typical mistake people make. They declare function as public
, assign it through the Editor, then mistakenly change it from public
to private
. This should work but can cause problem in the future.
This can be done by simply checking if type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic);
is null
.
If the function exist, show a message that warns you that this function's access modifier has been changed from public
to private
and should be changed back to public
.
If the function does not exist, show a message that warns you that this function does no longer exist or has been re-named.
Below is a script that performs everything I mentioned above. Attach it to an empty GameObject and it will do its job anytime you run the game in the Editor.
using System;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;
public class MissingOnClickDetector : MonoBehaviour
{
void Awake()
{
//Debug.Log("Class exist? " + classExist("ok.ButtonCallBackTest"));
searchForMissingOnClickFunctions();
}
void searchForMissingOnClickFunctions()
{
//Find all Buttons in the scene including hiding ones
Button[] allButtonScriptsInScene = Resources.FindObjectsOfTypeAll<Button>() as Button[];
for (int i = 0; i < allButtonScriptsInScene.Length; i++)
{
detectButtonError(allButtonScriptsInScene[i]);
}
}
//Searches each registered onClick function in each class
void detectButtonError(Button button)
{
for (int i = 0; i < button.onClick.GetPersistentEventCount(); i++)
{
//Get the target class name
UnityEngine.Object objectName = button.onClick.GetPersistentTarget(i);
//Get the function name
string methodName = button.onClick.GetPersistentMethodName(i); ;
//////////////////////////////////////////////////////CHECK CLASS/SCRIPT EXISTANCE/////////////////////////////////////////
//Check if the class that holds the function is null then exit if it is
if (objectName == null)
{
Debug.Log("<color=blue>Button \"" + button.gameObject.name +
"\" is missing the script that has the supposed button callback function. " +
"Please check if this script still exist or has been renamed</color>", button.gameObject);
continue; //Don't run code below
}
//Get full target class name(including namespace)
string objectFullNameWithNamespace = objectName.GetType().FullName;
//Check if the class that holds the function exist then exit if it does not
if (!classExist(objectFullNameWithNamespace))
{
Debug.Log("<color=blue>Button \"" + button.gameObject.name +
"\" is missing the script that has the supposed button callback function. " +
"Please check if this script still exist or has been renamed</color>", button.gameObject);
continue; //Don't run code below
}
//////////////////////////////////////////////////////CHECK FUNCTION EXISTANCE/////////////////////////////////////////
//Check if function Exist as public (the registered onClick function is ok if this returns true)
if (functionExistAsPublicInTarget(objectName, methodName))
{
//No Need to Log if function exist
//Debug.Log("<color=green>Function Exist</color>");
}
//Check if function Exist as private
else if (functionExistAsPrivateInTarget(objectName, methodName))
{
Debug.Log("<color=yellow>The registered Function \"" + methodName + "\" Exist as a private function. Please change \"" + methodName +
"\" function from the \"" + objectFullNameWithNamespace + "\" script to a public Access Modifier</color>", button.gameObject);
}
//Function does not even exist at-all
else
{
Debug.Log("<color=red>The \"" + methodName + "\" function Does NOT Exist in the \"" + objectFullNameWithNamespace + "\" script</color>", button.gameObject);
}
}
}
//Checks if class exit or has been renamed
bool classExist(string className)
{
Type myType = Type.GetType(className);
return myType != null;
}
//Checks if functions exist as public function
bool functionExistAsPublicInTarget(UnityEngine.Object target, string functionName)
{
Type type = target.GetType();
MethodInfo targetinfo = type.GetMethod(functionName);
return targetinfo != null;
}
//Checks if functions exist as private function
bool functionExistAsPrivateInTarget(UnityEngine.Object target, string functionName)
{
Type type = target.GetType();
MethodInfo targetinfo = type.GetMethod(functionName, BindingFlags.Instance | BindingFlags.NonPublic);
return targetinfo != null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With