update: 完善push图标生成工具
parent
794673c272
commit
9d08938d77
|
|
@ -1,2 +1,2 @@
|
|||
target=android-9
|
||||
android.library=true
|
||||
android.library=`true`
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
namespace Guru.Editor
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Create androidlib assets
|
||||
/// </summary>
|
||||
public class AndroidLibHelper
|
||||
{
|
||||
|
||||
private static readonly string PluginsRoot = "Plugins/Android";
|
||||
private static readonly string Extends = "androidlib";
|
||||
private static readonly string ProjectPropertiesName = "project.properties";
|
||||
private static readonly string ProjectPropertiesContent= "target=android-9\nandroid.library=true";
|
||||
private static readonly string AndroidManifestName = "AndroidManifest.xml";
|
||||
private static readonly string AndroidManifestContent = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"{0}\"\n android:versionCode=\"1\"\n android:versionName=\"1.0\">\n</manifest>";
|
||||
|
||||
|
||||
public static bool IsEmbeddedAndroidLibExists(string fileName)
|
||||
{
|
||||
string dir = Path.GetFullPath($"{Application.dataPath}/{PluginsRoot}/{fileName}.{Extends}");
|
||||
return Directory.Exists(dir);
|
||||
}
|
||||
|
||||
|
||||
public static string CreateLibRoot(string packageName, string fileName = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName)) return "";
|
||||
|
||||
if(string.IsNullOrEmpty(fileName)) fileName = packageName;
|
||||
|
||||
string dir = Path.GetFullPath($"{Application.dataPath}/{PluginsRoot}/{fileName}.{Extends}");
|
||||
if (Directory.Exists(dir))
|
||||
{
|
||||
return dir;
|
||||
}
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
string path = "";
|
||||
string content = "";
|
||||
|
||||
//------ Create project.properties ------
|
||||
content = ProjectPropertiesContent;
|
||||
path = $"{dir}/{ProjectPropertiesName}";
|
||||
File.WriteAllText(path, content);
|
||||
// ------ Create AndroidManifest.xml ------
|
||||
content = AndroidManifestContent.Replace("{0}", packageName);
|
||||
path = $"{dir}/{AndroidManifestName}";
|
||||
File.WriteAllText(path, content);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ee3d47ab5d544373ae6a43fdd36d96fb
|
||||
timeCreated: 1711761343
|
||||
|
|
@ -67,7 +67,7 @@ namespace Guru.Editor
|
|||
{
|
||||
if (e != null)
|
||||
{
|
||||
if (e.HasAttribute("android:name"))
|
||||
if (e.HasAttribute("name", NamespaceAndroid))
|
||||
{
|
||||
if (e.Attributes["android:name"].Value == ValOptimizeInitialization) item1 = 1;
|
||||
if (e.Attributes["android:name"].Value == ValOptimizeAdLoading) item2 = 1;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,257 @@
|
|||
|
||||
|
||||
|
||||
namespace Guru.Editor
|
||||
{
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Android 配置修改器
|
||||
/// </summary>
|
||||
public class MainManifestDoc
|
||||
{
|
||||
private const string TargetPath = "Plugins/Android/AndroidManifest.xml";
|
||||
private const string XmlnsAndroid = "xmlns:android";
|
||||
private const string NamespaceAndroid = "http://schemas.android.com/apk/res/android";
|
||||
private const string XmlnsTools= "xmlns:tools";
|
||||
private const string NamespaceTools = "http://schemas.android.com/tools";
|
||||
|
||||
|
||||
|
||||
private XmlDocument _doc;
|
||||
public XmlDocument Doc => _doc;
|
||||
|
||||
private string _docPath;
|
||||
private bool _isReady = false;
|
||||
|
||||
private XmlElement _manifestNode;
|
||||
private XmlElement _applicationNode;
|
||||
private XmlNodeList _metadataList;
|
||||
private XmlNodeList _permissionList;
|
||||
|
||||
|
||||
#region Initiallize
|
||||
|
||||
/// <summary>
|
||||
/// 加载文件
|
||||
/// </summary>
|
||||
/// <param name="docPath"></param>
|
||||
/// <returns></returns>
|
||||
public static MainManifestDoc Load(string docPath = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(docPath))
|
||||
{
|
||||
docPath = Path.GetFullPath(Path.Combine(Application.dataPath, TargetPath));
|
||||
}
|
||||
|
||||
if (!File.Exists(docPath))
|
||||
{
|
||||
Debug.LogError($"--- File not found: {docPath}");
|
||||
return null;
|
||||
}
|
||||
|
||||
var mod = new MainManifestDoc();
|
||||
mod.ReadFromPath(docPath);
|
||||
return mod;
|
||||
}
|
||||
|
||||
public static MainManifestDoc Read(string xmlStr, string docPath = "")
|
||||
{
|
||||
var mod = new MainManifestDoc();
|
||||
mod.ReadFromXml(xmlStr, docPath);
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 从文件路径读取
|
||||
/// </summary>
|
||||
/// <param name="docPath"></param>
|
||||
public void ReadFromPath(string docPath)
|
||||
{
|
||||
_isReady = false;
|
||||
if (File.Exists(docPath))
|
||||
{
|
||||
_docPath = docPath;
|
||||
var xmlStr = File.ReadAllText(docPath);
|
||||
ReadFromXml(xmlStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ReadFromXml(string xmlStr, string docPath = "")
|
||||
{
|
||||
_doc = new XmlDocument();
|
||||
_doc.LoadXml(xmlStr);
|
||||
_docPath = docPath;
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the Doc
|
||||
/// </summary>
|
||||
private void Init()
|
||||
{
|
||||
// --- Root Nodes ---
|
||||
_manifestNode = _doc.SelectSingleNode("manifest") as XmlElement;
|
||||
_applicationNode = _doc.SelectSingleNode("manifest/application") as XmlElement;
|
||||
// --- Metadatas ---
|
||||
_metadataList = _applicationNode.SelectNodes("meta-data");
|
||||
// --- Permissions ---
|
||||
_permissionList = _applicationNode.SelectNodes("uses-permission");
|
||||
|
||||
AddXmlnsAndroid();
|
||||
AddXmlnsTools();
|
||||
_isReady = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save Doc
|
||||
/// </summary>
|
||||
public void Save(string docPath = "")
|
||||
{
|
||||
if (_isReady)
|
||||
{
|
||||
if(string.IsNullOrEmpty(docPath)) docPath = _docPath;
|
||||
if (!string.IsNullOrEmpty(docPath))
|
||||
{
|
||||
var dir = Directory.GetParent(docPath);
|
||||
if(!dir.Exists) dir.Create();
|
||||
_doc.Save(_docPath);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Node Opreation
|
||||
|
||||
|
||||
public static bool AddAttribute(XmlElement node, string key, string value)
|
||||
{
|
||||
if (node != null)
|
||||
{
|
||||
if (node.HasAttribute(key))
|
||||
{
|
||||
node.Attributes[key].Value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
node.SetAttribute(key, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region API
|
||||
|
||||
public bool AddXmlnsAndroid()
|
||||
{
|
||||
return AddAttribute(_manifestNode, XmlnsAndroid, NamespaceAndroid);
|
||||
}
|
||||
|
||||
public bool AddXmlnsTools()
|
||||
{
|
||||
return AddAttribute(_manifestNode, XmlnsTools, NamespaceTools);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Replace Item
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
public void AddReplaceItem(string item)
|
||||
{
|
||||
if (_manifestNode != null)
|
||||
{
|
||||
List<string> items = new List<string>(5);
|
||||
if (_manifestNode.HasAttribute("replace", NamespaceTools))
|
||||
{
|
||||
var arr = _manifestNode.GetAttribute("replace",NamespaceTools).Split(',');
|
||||
if(arr != null && arr.Length > 0)
|
||||
{
|
||||
items.AddRange(arr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!items.Contains(item)) items.Add(item);
|
||||
|
||||
_manifestNode.SetAttribute("replace", NamespaceTools, string.Join(",", items));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set metadata
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="valueName"></param>
|
||||
/// <param name="keyName"></param>
|
||||
public void SetMetadata(string key, string value, string valueName = "value", string keyName = "name")
|
||||
{
|
||||
_metadataList = _applicationNode?.SelectNodes("meta-data") ?? null;
|
||||
|
||||
XmlElement item = null;
|
||||
if (_metadataList != null)
|
||||
{
|
||||
foreach (XmlElement e in _metadataList)
|
||||
{
|
||||
// var nm = e.GetAttribute("name", NamespaceAndroid);
|
||||
if (e.GetAttribute(keyName, NamespaceAndroid) is string k && k == key)
|
||||
{
|
||||
item = e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
item = _doc.CreateElement("meta-data");
|
||||
_applicationNode?.AppendChild(item);
|
||||
}
|
||||
|
||||
item.SetAttribute(keyName, NamespaceAndroid, key);
|
||||
item.SetAttribute(valueName, NamespaceAndroid, value);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Output
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (_doc != null) return _doc.InnerXml;
|
||||
return this.ToString();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 89a1c7f77fcf4982adbbaf6dc61bd62d
|
||||
timeCreated: 1711505949
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
using System.Net;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Guru.Editor
|
||||
{
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
|
||||
public class PushIconHelper
|
||||
{
|
||||
public static readonly int targetWidth = 96; // 目标宽度
|
||||
public static readonly int targetHeight = 96;
|
||||
private static readonly string LibName = "SDKRes";
|
||||
private static readonly string PackageName = "com.guru.unity.res";
|
||||
private static readonly string IconName = "ic_notification.png";
|
||||
|
||||
private static readonly string ColorContent =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorAccent\">#{0}</color>\n</resources>";
|
||||
private static readonly string ValueContent =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <string name=\"default_notification_channel_id\" translatable=\"false\">{0}</string>\n</resources>";
|
||||
private static readonly string[] iconNames = new string[]
|
||||
{
|
||||
"drawable-mdpi",
|
||||
"drawable-hdpi",
|
||||
"drawable-xhdpi",
|
||||
"drawable-xxhdpi",
|
||||
"drawable-xxxhdpi"
|
||||
};
|
||||
|
||||
|
||||
private static string FcmChannelId = "fcm_default_channel";
|
||||
|
||||
/// <summary>
|
||||
/// 设置推送图标
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
/// <param name="color"></param>
|
||||
public static bool SetPushIconAssets(Texture2D source, Color color = default(Color))
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
Debug.LogError($"=== No Texture2D found ===");
|
||||
return false;
|
||||
}
|
||||
return DeployAllIcons(source, color);
|
||||
}
|
||||
|
||||
private static Texture2D ResizeTexture(Texture2D source, int newWidth, int newHeight)
|
||||
{
|
||||
MakeTextureReadable(source);
|
||||
|
||||
Texture2D result = new Texture2D(newWidth, newHeight);
|
||||
Color[] newColors = new Color[newWidth * newHeight];
|
||||
|
||||
for (int y = 0; y < newHeight; y++)
|
||||
{
|
||||
for (int x = 0; x < newWidth; x++)
|
||||
{
|
||||
// 应用一些缩放逻辑来获取新的颜色值
|
||||
newColors[x + y * newWidth] = source.GetPixelBilinear((float)x / newWidth * source.width, (float)y / newHeight * source.height);
|
||||
}
|
||||
}
|
||||
|
||||
result.SetPixels(newColors);
|
||||
result.Apply();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void MakeTextureReadable(Texture2D source)
|
||||
{
|
||||
if (source.isReadable) return;
|
||||
|
||||
var path = AssetDatabase.GetAssetPath(source);
|
||||
TextureImporter ti = (TextureImporter)AssetImporter.GetAtPath(path);
|
||||
if (!ti.isReadable)
|
||||
{
|
||||
ti.isReadable = true;
|
||||
ti.SaveAndReimport();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string ColorToHex(Color color)
|
||||
{
|
||||
return string.Format("{0:X2}{1:X2}{2:X2}", (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255));
|
||||
}
|
||||
|
||||
|
||||
private static bool DeployAllIcons(Texture2D source, Color color)
|
||||
{
|
||||
var dir = AndroidLibHelper.CreateLibRoot(PackageName, LibName);
|
||||
string path = "";
|
||||
string content = "";
|
||||
|
||||
var result = ResizeTexture(source, targetWidth, targetHeight);
|
||||
byte[] bytes = result.EncodeToPNG();
|
||||
|
||||
|
||||
var resPath = $"{dir}/res";
|
||||
if (!Directory.Exists(resPath))
|
||||
{
|
||||
Directory.CreateDirectory(resPath);
|
||||
}
|
||||
|
||||
File.WriteAllBytes($"{resPath}/{IconName}", bytes); // Base Icon;
|
||||
// ----- Build all Icons ------
|
||||
foreach (var iconName in iconNames)
|
||||
{
|
||||
var iconPath = $"{resPath}/{iconName}";
|
||||
if (!Directory.Exists(iconPath))
|
||||
{
|
||||
Directory.CreateDirectory(iconPath);
|
||||
}
|
||||
File.WriteAllBytes($"{iconPath}/{IconName}", bytes);
|
||||
}
|
||||
|
||||
var valuesPath = $"{resPath}/values";
|
||||
if (!Directory.Exists(valuesPath)) Directory.CreateDirectory(valuesPath);
|
||||
|
||||
// ----- Build colors.xml ------
|
||||
path = $"{valuesPath}/colors.xml";
|
||||
content = ColorContent.Replace("{0}", ColorToHex(color));
|
||||
File.WriteAllText(path, content);
|
||||
// ----- Build strings.xml ------
|
||||
path = $"{valuesPath}/strings.xml";
|
||||
content = ValueContent.Replace("{0}", FcmChannelId);
|
||||
File.WriteAllText(path, content);
|
||||
|
||||
// ----- Inject AndroidManifest.xml ------
|
||||
var doc = MainManifestDoc.Load();
|
||||
if (doc != null)
|
||||
{
|
||||
doc.SetMetadata("com.google.firebase.messaging.default_notification_icon", "@drawable/ic_notification", valueName:"resource");
|
||||
doc.SetMetadata("com.google.firebase.messaging.default_notification_color", "@color/colorAccent", valueName:"resource");
|
||||
doc.SetMetadata("com.google.firebase.messaging.default_notification_channel_id", "@string/default_notification_channel_id");
|
||||
doc.Save();
|
||||
Debug.Log("<color=#88ff00> --- Push Icon Build Success --- </color>");
|
||||
return true;
|
||||
}
|
||||
|
||||
Debug.LogError("AndroidManifest.xml not found ...");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 39d65f42b9694641b0c3509262aca1d4
|
||||
timeCreated: 1711724404
|
||||
|
|
@ -395,6 +395,11 @@ namespace Guru.Editor
|
|||
GUI_OnConfigEnabled();
|
||||
}
|
||||
|
||||
GUILayout.Space(10);
|
||||
|
||||
// Push
|
||||
GUI_PushIconMaker();
|
||||
|
||||
}
|
||||
|
||||
private void GUI_WindowTitle()
|
||||
|
|
@ -1000,6 +1005,60 @@ namespace Guru.Editor
|
|||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Push Icon Maker
|
||||
|
||||
private bool _showSegmentPush = false;
|
||||
private Texture2D _pushIconTexture;
|
||||
private Color _pushIconColor = Color.white;
|
||||
|
||||
private void GUI_PushIconMaker()
|
||||
{
|
||||
float btnH = 24;
|
||||
|
||||
|
||||
_showSegmentPush = EditorGUILayout.Foldout(_showSegmentPush, "[ Push Icon ]");
|
||||
|
||||
// EditorGUILayout.LabelField("[ Push Icon ]", StyleItemTitle);
|
||||
|
||||
if (_showSegmentPush)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.BeginHorizontal("box");
|
||||
EditorGUILayout.LabelField("Icon ( 96x96 PNG )");
|
||||
_pushIconTexture = EditorGUILayout.ObjectField( _pushIconTexture, typeof(Texture2D), false) as Texture2D;
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal("box");
|
||||
EditorGUILayout.LabelField("Icon Color");
|
||||
_pushIconColor = EditorGUILayout.ColorField(_pushIconColor);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (null != _pushIconTexture)
|
||||
{
|
||||
GUI_Button("CREATE PUSH ASSETS", () =>
|
||||
{
|
||||
if (PushIconHelper.SetPushIconAssets(_pushIconTexture, _pushIconColor))
|
||||
{
|
||||
EditorUtility.DisplayDialog("Set Push Icon", "Push Icon assets created success!", "OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorUtility.DisplayDialog("Set Push Icon", "Push Icon assets created failed!", "Well...");
|
||||
}
|
||||
}, null, GUILayout.Height(btnH));
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
"GuruSDK",
|
||||
"Guru.LitJson",
|
||||
"Guru.Runtime",
|
||||
"MaxSdk.Scripts.IntegrationManager.Editor"
|
||||
"MaxSdk.Scripts.IntegrationManager.Editor",
|
||||
"Guru.Editor"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Guru
|
|||
|
||||
public partial class GuruSDK: MonoBehaviour
|
||||
{
|
||||
public const string Version = "1.0.9";
|
||||
public const string Version = "1.0.10";
|
||||
public const string Tag = "[Guru]";
|
||||
public const string ServicesConfigKey = "guru_services";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "com.guru.unity.sdk",
|
||||
"displayName": "Guru SDK",
|
||||
"version": "1.0.9",
|
||||
"version": "1.0.10",
|
||||
"description": "Guru SDK for unity project",
|
||||
"unity": "2020.3",
|
||||
"author":{
|
||||
|
|
|
|||
Loading…
Reference in New Issue