179 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			179 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C#
		
	
	
| 
 | |
| 
 | |
| #if UNITY_ANDROID
 | |
| 
 | |
| namespace Guru.Notification
 | |
| {
 | |
|     using System;
 | |
|     using System.IO;
 | |
|     using UnityEditor.Android;
 | |
|     using System.Xml;
 | |
|     
 | |
|     public class PostCustomActivity: IPostGenerateGradleAndroidProject
 | |
|     {
 | |
|         private const int POST_ORDER = 10;
 | |
|         private const string K_PREMISSION_POST_NOTIFICATIONS = "android.permission.POST_NOTIFICATIONS";
 | |
|         private const string K_CUSTOM_NOTIFICATION_ACTIVITY = "custom_notification_android_activity";
 | |
|         private const string V_DEFAULT_GURU_ACTIVITY = "com.google.firebase.messaging.MessageForwardingService";
 | |
|         const string K_ANDROID_NAMESPACE_URI = "http://schemas.android.com/apk/res/android";
 | |
|         
 | |
|         public int callbackOrder => POST_ORDER;
 | |
| 
 | |
|         public void OnPostGenerateGradleAndroidProject(string path)
 | |
|         {
 | |
|             SetupAndroidManifest(path);
 | |
|         }
 | |
|         
 | |
|         /// <summary>
 | |
|         /// 设置 Android Manifest
 | |
|         /// </summary>
 | |
|         /// <param name="projectPath"></param>
 | |
|         /// <exception cref="FileNotFoundException"></exception>
 | |
|         private void SetupAndroidManifest(string projectPath)
 | |
|         {
 | |
|             var manifestPath = $"{projectPath}/src/main/AndroidManifest.xml";
 | |
|             if (!File.Exists(manifestPath))
 | |
|                 throw new FileNotFoundException($"'{manifestPath}' doesn't exist.");
 | |
| 
 | |
|             XmlDocument manifestDoc = new XmlDocument();
 | |
|             manifestDoc.Load(manifestPath);
 | |
|             
 | |
|             InjectAndroidManifest(manifestPath, manifestDoc);
 | |
| 
 | |
|             manifestDoc.Save(manifestPath);
 | |
|         }
 | |
|         
 | |
|         internal static void InjectAndroidManifest(string manifestPath, XmlDocument manifestDoc)
 | |
|         {
 | |
|             string mainActivity = GetLauncherActivity(manifestDoc);
 | |
| 
 | |
|             AppendAndroidMetadataField(manifestPath, manifestDoc, K_CUSTOM_NOTIFICATION_ACTIVITY, mainActivity);
 | |
|             AppendAndroidPermissionField(manifestPath, manifestDoc, K_PREMISSION_POST_NOTIFICATIONS);
 | |
|             
 | |
|             UnityEngine.Debug.Log($"<color=#88ff00>Add custom notification activity: {mainActivity} success!!</color>");
 | |
|         }
 | |
|         
 | |
|         internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string name, string maxSdk = null)
 | |
|         {
 | |
|             AppendAndroidPermissionField(manifestPath, xmlDoc, "uses-permission", name, maxSdk);
 | |
|         }
 | |
|         
 | |
|         internal static void AppendAndroidPermissionField(string manifestPath, XmlDocument xmlDoc, string tagName, string name, string maxSdk)
 | |
|         {
 | |
|             var manifestNode = xmlDoc.SelectSingleNode("manifest");
 | |
|             if (manifestNode == null)
 | |
|                 throw new ArgumentException(string.Format("Missing 'manifest' node in '{0}'.", manifestPath));
 | |
| 
 | |
|             XmlElement metaDataNode = null;
 | |
|             foreach (XmlNode node in manifestNode.ChildNodes)
 | |
|             {
 | |
|                 if (!(node is XmlElement) || node.Name != tagName)
 | |
|                     continue;
 | |
| 
 | |
|                 var element = (XmlElement)node;
 | |
|                 var elementName = element.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
 | |
|                 if (elementName == name)
 | |
|                 {
 | |
|                     if (maxSdk == null)
 | |
|                         return;
 | |
|                     var maxSdkAttr = element.GetAttribute("maxSdkVersion", K_ANDROID_NAMESPACE_URI);
 | |
|                     if (!string.IsNullOrEmpty(maxSdkAttr))
 | |
|                         return;
 | |
|                     metaDataNode = element;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (metaDataNode == null)
 | |
|             {
 | |
|                 metaDataNode = xmlDoc.CreateElement(tagName);
 | |
|                 metaDataNode.SetAttribute("name", K_ANDROID_NAMESPACE_URI, name);
 | |
|             }
 | |
|             if (maxSdk != null)
 | |
|                 metaDataNode.SetAttribute("maxSdkVersion", K_ANDROID_NAMESPACE_URI, maxSdk);
 | |
| 
 | |
|             manifestNode.AppendChild(metaDataNode);
 | |
|         }
 | |
|         
 | |
|         internal static void AppendAndroidMetadataField(string manifestPath, XmlDocument xmlDoc, string name, string value)
 | |
|         {
 | |
|             var applicationNode = xmlDoc.SelectSingleNode("manifest/application");
 | |
|             if (applicationNode == null)
 | |
|                 throw new ArgumentException(string.Format("Missing 'application' node in '{0}'.", manifestPath));
 | |
| 
 | |
|             var nodes = xmlDoc.SelectNodes("manifest/application/meta-data");
 | |
|             if (nodes != null)
 | |
|             {
 | |
|                 // Check if there is a 'meta-data' with the same name.
 | |
|                 foreach (XmlNode node in nodes)
 | |
|                 {
 | |
|                     var element = node as XmlElement;
 | |
|                     if (element == null)
 | |
|                         continue;
 | |
| 
 | |
|                     var elementName = element.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
 | |
|                     if (elementName == name)
 | |
|                     {
 | |
|                         element.SetAttribute("value", K_ANDROID_NAMESPACE_URI, value);
 | |
|                         return;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             XmlElement metaDataNode = xmlDoc.CreateElement("meta-data");
 | |
|             metaDataNode.SetAttribute("name", K_ANDROID_NAMESPACE_URI, name);
 | |
|             metaDataNode.SetAttribute("value", K_ANDROID_NAMESPACE_URI, value);
 | |
| 
 | |
|             applicationNode.AppendChild(metaDataNode);
 | |
|         }
 | |
|         
 | |
|         internal static string GetLauncherActivity(XmlDocument xmlDoc)
 | |
|         {
 | |
|             var applicationNode = xmlDoc.SelectSingleNode("manifest/application");
 | |
|             if (applicationNode == null)
 | |
|                 throw new ArgumentException($"Missing 'application' node in doc.");
 | |
|             
 | |
|             var nodes = xmlDoc.SelectNodes("manifest/application/activity");
 | |
|             if (nodes != null)
 | |
|             {
 | |
|                 foreach (XmlNode node in nodes)
 | |
|                 {
 | |
|                     var activityNode = node as XmlElement;
 | |
|                     if (activityNode == null)
 | |
|                         continue;
 | |
| 
 | |
|                     if (activityNode.HasChildNodes)
 | |
|                     {
 | |
|                         var intentFilterNode = activityNode.SelectSingleNode("intent-filter");
 | |
|                        
 | |
|                         if(intentFilterNode == null || !intentFilterNode.HasChildNodes)
 | |
|                             continue;
 | |
|                         
 | |
|                         foreach (XmlElement childNode in intentFilterNode)
 | |
|                         {
 | |
|                             if(childNode == null) continue;
 | |
|                             
 | |
|                             // 判断 action/category 二者取其一
 | |
|                             if (childNode.Name == "action" && childNode.InnerXml.Contains("android.intent.action.MAIN"))
 | |
|                             {
 | |
|                                 var activityName = activityNode.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
 | |
|                                 return activityName;
 | |
|                             }
 | |
|                             
 | |
|                             if (childNode.Name == "category" && childNode.InnerXml.Contains("android.intent.category.LAUNCHER"))
 | |
|                             {
 | |
|                                 var activityName = activityNode.GetAttribute("name", K_ANDROID_NAMESPACE_URI);
 | |
|                                 return activityName;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return V_DEFAULT_GURU_ACTIVITY;
 | |
|         }
 | |
|         
 | |
|     }
 | |
| }
 | |
| 
 | |
| #endif
 |