需求
最近一直在接sdk,同一个工程要接好几个sdk,比如小米的广告sdk,vivo的支付和广告,oppo的游戏中心,
然后每换一个sdk打包我都要从新复制一个工程,然后去接sdk,再在里面打包,这样做很浪费时间,也很浪费精力,所以想了很长时间,大致想出来两种解决方案
解决方案
1.使用Android的多渠道打包方案,配置一个个库文件,引用那个直接导出
优点:大部分工作集中在Android端和unity分离,无论是耦合性还是效率都不错,能够很完美的解决需求
缺点:我不会配置
2.使用unity窗口,将每一个版本的包的配置信息记录下来,然后将接好的文件放到指定的目录,,每次更换打包的话通过配置信息将plugins从别的地方复制进unity,然后使用编辑器打包
优点:除了对接sdk还是要手动去接,其他的内容全部放在unity端来处理,更加方便我来控制
缺点:或者说这是我想到的两种方案都出现的问题,,解耦 无论是c#还是java,都是要编译的,但是每个包要处理的反应是不一样的,有的要显示广告有的要显示支付,这是要处理的
还好的是,我一直比较喜欢将项目解耦和,让各个部分互不干扰,通过一些方法,大致实现了这种解耦
然后上代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using LitJson;
using System;
public class ProjectBuildForAndroid : EditorWindow
{
string JsonPath = @"F:\SDK配置\欢乐玻璃杯\Json";
string FilePath = @"F:\SDK配置\欢乐玻璃杯\File";
DictionaryJsonData> Dic = new DictionaryJsonData>();
//公用信息 开始
string ConfigureJsonName = "";
string ProductName = "";
string PacketageName = "";
string Version = "";
string BundleVersionCode = "";
string PluginsPath = "";
string ScriptsPath = "";
static JsonData lookJson;
ProjectBuildForAndroid()
{
this.titleContent = new GUIContent("ProjectBuildForAndroid");
titleContent.text = "安卓设置";
getConfigureJson();
}
[MenuItem("Tool/自定义打包")]
static void showWindow()
{
EditorWindow.GetWindow(typeof(ProjectBuildForAndroid));
}
void OnGUI()
{
GUILayout.BeginVertical();
//绘制标题
GUILayout.Space(10);
GUI.skin.label.fontSize = 24;
GUI.skin.label.alignment = TextAnchor.MiddleCenter;
GUILayout.Label("自定义打包");
GUILayout.Label(System.DateTime.Now + "");
GUILayout.EndVertical();
GUILayout.BeginVertical();
GUILayout.Space(10);
if (Dic.Count >= 0)
{
foreach (KeyValuePairJsonData> item in Dic)
{
if (GUILayout.Button(item.Key.ToString().Split('.')[0], GUILayout.Width(200), GUILayout.ExpandWidth(true)))
{
lookJson = item.Value;
ShowSetting();
}
}
}
GUILayout.BeginHorizontal();
if (GUILayout.Button("查看信息", GUILayout.Height(60),GUILayout.Width(200)))
{
if (lookJson==null )
{
this.ShowNotification(new GUIContent("暂无提示信息,请选择要打包的配置"));
return;
}
string txt = "";
for (int i = 0; i < lookJson.Count; i++)
{
txt += lookJson[i].ToString() + "\n";
}
this.ShowNotification(new GUIContent(txt));
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUILayout.BeginVertical( );
GUILayout.Space(10);
GUILayout.Label("配置信息");
ConfigureJsonName = EditorGUILayout.TextField("配置信息名称:", ConfigureJsonName);
ProductName = EditorGUILayout.TextField("产品名字:", ProductName);
PacketageName = EditorGUILayout.TextField("包名:", PacketageName);
Version = EditorGUILayout.TextField("版本", Version);
BundleVersionCode = EditorGUILayout.TextField("代码版本:", BundleVersionCode);
GUILayout.Space(10);
GUILayout.Label("复制Plugins");
PluginsPath = EditorGUILayout.TextField("Plugins路径:", PluginsPath);
ScriptsPath = EditorGUILayout.TextField("SDK脚本路径:", ScriptsPath);
GUILayout.BeginHorizontal();
if (GUILayout.Button("保存配置信息",GUILayout.Height(60), GUILayout.Width(200)))
{
SaveConfigureJson();
}
if (GUILayout.Button("修改配置信息", GUILayout.Height(60), GUILayout.Width(200)))
{
ChangeConfigureJson();
}
if (GUILayout.Button("复制脚本文件", GUILayout.Height(60), GUILayout.Width(200)))
{
CopyFile();
}
if (GUILayout.Button("开始打包", GUILayout.Height(60), GUILayout.Width(200)))
{
Build();
}
GUILayout.EndHorizontal();
GUILayout.EndVertical();
}
//得到所有的以保存渠道的信息
void getConfigureJson()
{
DirectoryInfo dir = new DirectoryInfo(JsonPath);
if (dir.GetFiles().Length ==0)
{
this.ShowNotification(new GUIContent("暂无配置信息"));
return;
}
FileInfo[] Jsonfiles = dir.GetFiles();
for (int i = 0; i < Jsonfiles.Length; i++)
{
string name = Jsonfiles[i].Name;
string txt= File.ReadAllText(Jsonfiles[i].FullName, Encoding.UTF8);
JsonData obj = JsonMapper.ToObject(txt);
if(!Dic.ContainsKey (name))
Dic.Add(name, obj);
}
if (lookJson!=null )
{
ShowSetting();
}
}
//用于保存当前信息
void SaveConfigureJson()
{
if (Dic.ContainsKey (ConfigureJsonName+".json"))
{
this.ShowNotification(new GUIContent("该配置已存在"));
return;
}
if (!Directory.Exists (JsonPath ))
{
Directory.CreateDirectory(JsonPath );
}
JsonData saveJson = new JsonData();
saveJson["ConfigureJsonName"] = ConfigureJsonName;
saveJson["ProductName"] = ProductName;
saveJson["PacketageName"] = PacketageName;
saveJson["Version"] = Version;
saveJson["BundleVersionCode"] = BundleVersionCode;
saveJson["PluginsPath"] = FilePath + "/" + ConfigureJsonName + "/Plugins";
saveJson["ScriptsPath"] = FilePath + "/" + ConfigureJsonName + "/SDK";
string str = saveJson.ToJson();
StreamWriter sw = new StreamWriter(JsonPath+ "/" + ConfigureJsonName + ".json");
sw.WriteLine(str);
sw.Close();
if (!Directory.Exists (FilePath+"/"+ ConfigureJsonName))
{
Directory.CreateDirectory(FilePath + "/" + ConfigureJsonName+"/Plugins");
Directory.CreateDirectory(FilePath + "/" + ConfigureJsonName + "/SDK");
}
getConfigureJson();
}
void ChangeConfigureJson()
{
if (!Dic.ContainsKey(ConfigureJsonName + ".json"))
{
this.ShowNotification(new GUIContent("该配置不存在,请直接保存配置信息"));
return;
}
else
{
Dic.Remove(ConfigureJsonName + ".json");
File.Delete(JsonPath + "/" + ConfigureJsonName + ".json");
lookJson["ConfigureJsonName"] = ConfigureJsonName;
lookJson["ProductName"] = ProductName;
lookJson["PacketageName"] = PacketageName;
lookJson["Version"] = Version;
lookJson["BundleVersionCode"] = BundleVersionCode;
lookJson["PluginsPath"] = PluginsPath;
lookJson["ScriptsPath"] = ScriptsPath;
string str = lookJson.ToJson();
StreamWriter sw = new StreamWriter(JsonPath + "/" + ConfigureJsonName + ".json");
sw.WriteLine(str);
sw.Close();
getConfigureJson();
}
}
bool isCopyOver;
void CopyFile()
{
string PluginsFilePath = FilePath + "/"+ ConfigureJsonName+ "/Plugins";
if (!Directory.Exists(PluginsFilePath))
{
this.ShowNotification(new GUIContent("要复制的Plugins文件不存在,请注意"));
return;
}
string ScriptsFilePath = FilePath + "/" + ConfigureJsonName + "/SDK/SDKManager.cs";
if (!File.Exists(ScriptsFilePath))
{
this.ShowNotification(new GUIContent("要复制的SDKManager文件不存在,请注意"));
return;
}
string Pluginspath = Application.dataPath+"/Plugins";
if (Directory .Exists (Pluginspath))
{
FileAttributes attr = File.GetAttributes(Pluginspath);
if (attr == FileAttributes.Directory)
{
Directory.Delete(Pluginspath, true);
}
else
{
File.Delete(Pluginspath);
}
}
string Scriptspath = Application.dataPath + "/SDK/SDKManager.cs";
if (File .Exists(Scriptspath))
{
File.Delete(Scriptspath);
}
CopyOldLabFilesToNewLab(PluginsFilePath, Pluginspath);
while (isCopyOver==false )
{
}
FileInfo ScriptSDKManager = new FileInfo(ScriptsFilePath);
ScriptSDKManager.CopyTo(Scriptspath);
}
void Build()
{
PlayerSettings.companyName = ConfigureJsonName;
PlayerSettings.productName = ProductName;
PlayerSettings.Android.keystoreName = @"C:\Users\administered\Desktop\签名\Sg3.keystore";
PlayerSettings.Android.keyaliasName = "Sg3.keystore";
PlayerSettings.Android.keystorePass = "morefuntek";
PlayerSettings.Android.keyaliasPass = "morefuntek";
PlayerSettings.applicationIdentifier = PacketageName;
PlayerSettings.bundleVersion = Version;
PlayerSettings.Android.bundleVersionCode =int.Parse (BundleVersionCode) ;
string apkName = string.Format(@"C:\Users\administered\Desktop\Build\{0}.apk", ConfigureJsonName);
List levels = new List();
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes)
{
if (!scene.enabled) continue;
// 获取有效的 Scene
levels.Add(scene.path);
}
BuildTarget buildTarget = BuildTarget.Android;
// 切换到 Android 平台
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android,buildTarget);
string res = BuildPipeline.BuildPlayer(levels.ToArray(), apkName, buildTarget, BuildOptions.None);
if (res.Length > 0)
{
throw new Exception(" BuildPlayer failure: " + res);
}
AssetDatabase.Refresh();
}
void ShowSetting()
{
ConfigureJsonName = lookJson["ConfigureJsonName"].ToString();
ProductName = lookJson["ProductName"].ToString();
PacketageName = lookJson["PacketageName"].ToString();
Version = lookJson["Version"].ToString();
BundleVersionCode = lookJson["BundleVersionCode"].ToString();
PluginsPath = lookJson["PluginsPath"].ToString();
ScriptsPath=lookJson["ScriptsPath"].ToString ();
}
public void CopyOldLabFilesToNewLab(string sourcePath, string savePath)
{
if (!Directory.Exists(savePath))
{
Directory.CreateDirectory(savePath);
}
#region //拷贝labs文件夹到savePath下
try
{
string[] labDirs = Directory.GetDirectories(sourcePath);//目录
string[] labFiles = Directory.GetFiles(sourcePath);//文件
if (labFiles.Length > 0)
{
for (int i = 0; i < labFiles.Length; i++)
{
if (Path.GetExtension(labFiles[i]) != ".meta")//排除.lab文件
{
File.Copy(sourcePath + "\\" + Path.GetFileName(labFiles[i]), savePath + "\\" + Path.GetFileName(labFiles[i]), true);
}
}
}
if (labDirs.Length > 0)
{
for (int j = 0; j < labDirs.Length; j++)
{
Directory.GetDirectories(sourcePath + "\\" + Path.GetFileName(labDirs[j]));
//递归调用
CopyOldLabFilesToNewLab(sourcePath + "\\" + Path.GetFileName(labDirs[j]), savePath + "\\" + Path.GetFileName(labDirs[j]));
}
}
}
catch (Exception)
{
isCopyOver = false;
}
#endregion
isCopyOver = true;
}
}
这就是全部的代码了,想了几天的时间,plugins文件夹和SDkmanager.cs文件是要先写好的,plugins是放接好的sdk和Android文件 而 SDKMnaager.cs是解耦的关键 是最后跟sdk交接的部分
这里采用了消息的传递机制,SDKEventDisPatcer.cs是消息传递中心 SDKManager.cs是真正接受消息,并与sdk交互的部分,后面直接更换这个脚本就行了 SDKUI.cs是需要拖到物体上的,里面发出各种消息 UnitySingleton.cs 是单例类
先说一下思路,再上代码 SDKUI.cs是要挂到物体上的,由这个脚本负责消息的发出 和SDKManager的初始化 SDKEventDisPatcer.cs负责将消息发给已经注册消息的脚本,而SDKManager会根据不同的情况,注册并接受不同的消息从而实现解耦
要换sdk的话只需要更换plugins和更换sdkmanager就行了
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SDKEventDisPatcer : Singleton
{
public delegate void OnActionHandle(object obj = null);
public Dictionary<ushort, List> dic = new Dictionary<ushort, List>();
public void AddEventListener(ushort ProtoCode, OnActionHandle handle)
{
if (dic.ContainsKey(ProtoCode))
{
dic[ProtoCode].Add(handle);
}
else
{
List listHandle = new List();
listHandle.Add(handle);
dic[ProtoCode] = listHandle;
}
}
public void RemeiveEventListener(ushort ProtoCode, OnActionHandle handle)
{
if (dic.ContainsKey(ProtoCode))
{
List listhandle = dic[ProtoCode];
listhandle.Remove(handle);
if (listhandle.Count == 0)
{
dic.Remove(ProtoCode);
}
}
}
public void Dispatch(ushort ProtoCode, object obj=null)
{
if (dic.ContainsKey(ProtoCode))
{
List listhandle = dic[ProtoCode];
if (listhandle != null && listhandle.Count > 0)
{
for (int i = 0; i < listhandle.Count; i++)
{
if (listhandle[i] != null)
{
listhandle[i](obj);
}
}
}
}
}
public int GetlisthandleCount(ushort ProtoCode)
{
return dic[ProtoCode].Count;
}
}
public class EvevtCode
{
public const ushort Pay = 1;
public const ushort Banner = 2;
public const ushort Inter = 3;
public const ushort Video = 4;
public const ushort Splash = 5;
}
SDKManager
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// /////////////////
///
public class SDKManager : UnitySingleton {
protected override void Awake()
{
base.Awake();
SDKEventDisPatcer.Instance.AddEventListener(EvevtCode.Pay, OnPay);
SDKEventDisPatcer.Instance.AddEventListener(EvevtCode.Banner, OnBanner);
SDKEventDisPatcer.Instance.AddEventListener(EvevtCode.Inter, OnInter);
SDKEventDisPatcer.Instance.AddEventListener(EvevtCode.Video, OnVideo);
SDKEventDisPatcer.Instance.AddEventListener(EvevtCode.Splash, OnSplash);
}
AndroidJavaObject ao;
void Start()
{
AndroidJavaClass ac = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
ao = ac.GetStatic("currentActivity");
}
public void LateUpdate()
{
if (Application.platform == RuntimePlatform.Android && (Input.GetKeyDown(KeyCode.Escape)))
{
try
{
ao.CallStatic("exitMyGame");
}
catch (System.Exception)
{}
}
}
private void OnSplash(object obj)
{
}
private void OnVideo(object obj)
{
ao.Call("showVideoAd");
}
private void OnInter(object obj)
{
ao.Call("showInterAd");
}
private void OnBanner(object obj)
{
ao.Call("showBannerAd");
}
private void OnPay(object obj)
{
ao.Call("doPay");
}
}
SDKUI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SDKUI : MonoBehaviour {
private void Awake()
{
GameObject SDKManager = GameObject.Find("SDKManager");
if (SDKManager==null )
{
SDKManager = new GameObject("SDKManager");
SDKManager.AddComponent();
}
}
// Use this for initialization
void Start () {
switch (gameObject.name )
{
case "Button":
GetComponent
UnitySingleton
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UnitySingleton : MonoBehaviour where T : Component
{
public static T Instance;
protected virtual void Awake()
{
if (Instance)
{
DestroyImmediate(this);
}
else
{
DontDestroyOnLoad(this );
Instance = this as T;
}
}
}
public abstract class Singleton where T : new()
{
private static T _instance;
static object _lock = new object();
public static T Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
_instance = new T();
}
}
return _instance;
}
}
}
以上就是全部的代码,写的很简陋,日后会一点点更新的,有大神觉得那里写的不对或者可以优化的请直接说出,万分感谢,有不懂的同学也可以留言