Skip to content

Commit 68f576b

Browse files
Anna KocheshkovaMax
authored andcommitted
Add PostBuild setup for pushes android (#217)
* Firebase * Fix * + files * Move to PreBuild * Fix newlines * Package * download Play Services Resolver for Unity from GitHub * Fixes * Versions * Remove mobile-center * Remove line * Fix * Revert "Fix" This reverts commit df16917. * Fix * update build script * download Jar resolver from blob storage * call VersionHandler using reflection to avoid error during Play Services Resolver for Unity package import * Delete play-services-resolver-1.2.95.0.unitypackage * Update placeholder path * log error if Jar Resolver classes are not found
1 parent 6515991 commit 68f576b

File tree

10 files changed

+505
-3
lines changed

10 files changed

+505
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Assets/Plugins/Android/appcenter/res.meta
7373
Assets/Firebase/
7474
Assets/PlayServicesResolver/
7575
Assets/PlayServicesResolver.meta
76+
ProjectSettings/AndroidResolverDependencies.xml
7677

7778
# Cake
7879
CAKE_SCRIPT_TEMP*

Assets/AppCenter/Editor/AppCenterPreBuild.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public void OnPreprocessBuild(BuildTarget target, string path)
2424
{
2525
if (target == BuildTarget.Android)
2626
{
27+
var settings = AppCenterSettingsContext.SettingsInstance;
28+
if (settings.UsePush && AppCenter.Push != null)
29+
{
30+
FirebaseDependency.SetupPush();
31+
}
2732
AddStartupCode(new AppCenterSettingsMakerAndroid());
2833
}
2934
else if (target == BuildTarget.iOS)
Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
//
3+
// Licensed under the MIT license.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Reflection;
10+
using UnityEditor;
11+
using UnityEngine;
12+
13+
/// <summary>
14+
/// This file is used to define dependencies, and pass them along to a system which can resolve dependencies.
15+
/// </summary>
16+
public class FirebaseDependency
17+
{
18+
private const string GoogleServicesFileBasename = "google-services";
19+
private const string GoogleServicesInputFile = GoogleServicesFileBasename + ".json";
20+
private const string GoogleServicesOutputFile = GoogleServicesFileBasename + ".xml";
21+
private const string GoogleServicesOutputDirectory = "Assets/Plugins/Android/res/values";
22+
private const string GoogleServicesOutputPath = GoogleServicesOutputDirectory + "/" + GoogleServicesOutputFile;
23+
24+
private const string DefaultWebClientIdKey = "default_web_client_id";
25+
private const string FirebaseDatabaseUrlKey = "firebase_database_url";
26+
private const string GATrackingIdKey = "ga_trackingId";
27+
private const string GSMDefaultSenderIdKey = "gcm_defaultSenderId";
28+
private const string GoogleAPIKey = "google_api_key";
29+
private const string GoogleAppIdKey = "google_app_id";
30+
private const string CrashReportingApiKey = "google_crash_reporting_api_key";
31+
private const string GoogleStorageBucketKey = "google_storage_bucket";
32+
private const string ProjectIdKey = "project_id";
33+
34+
private const string FirebaseMessagingVersion = "17.0.0";
35+
private const string FirebaseCoreVersion = "16.0.1";
36+
37+
static void SetupDependencies()
38+
{
39+
#if UNITY_ANDROID
40+
// Setup the resolver using reflection as the module may not be available at compile time.
41+
Type versionHandler = Type.GetType("Google.VersionHandler, Google.VersionHandler, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null");
42+
if (versionHandler == null)
43+
{
44+
Debug.LogError("Unable to set up Android dependencies, class `Google.VersionHandler` is not found");
45+
return;
46+
}
47+
Type playServicesSupport = (Type)versionHandler.InvokeMember("FindClass", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[]
48+
{
49+
"Google.JarResolver", "Google.JarResolver.PlayServicesSupport"
50+
});
51+
if (playServicesSupport == null)
52+
{
53+
Debug.LogError("Unable to set up Android dependencies, class `Google.JarResolver.PlayServicesSupport` is not found");
54+
return;
55+
}
56+
object svcSupport = versionHandler.InvokeMember("InvokeStaticMethod", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[]
57+
{
58+
playServicesSupport, "CreateInstance", new object[] { "FirebaseMessaging", EditorPrefs.GetString("AndroidSdkRoot"), "ProjectSettings" }, null
59+
});
60+
versionHandler.InvokeMember("InvokeInstanceMethod", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[]
61+
{
62+
svcSupport, "DependOn", new object[] { "com.google.firebase", "firebase-messaging", FirebaseMessagingVersion },
63+
new Dictionary<string, object>() {
64+
{ "packageIds", new string[] { "extra-google-m2repository", "extra-android-m2repository" } },
65+
{ "repositories", null }
66+
}
67+
});
68+
versionHandler.InvokeMember("InvokeInstanceMethod", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[]
69+
{
70+
svcSupport, "DependOn",
71+
new object[] { "com.google.firebase", "firebase-core", FirebaseCoreVersion },
72+
new Dictionary<string, object>() {
73+
{ "packageIds", new string[] { "extra-google-m2repository", "extra-android-m2repository" } },
74+
{ "repositories", null }
75+
}
76+
});
77+
// Update editor project view.
78+
AssetDatabase.Refresh();
79+
#endif
80+
}
81+
82+
static string[] FindGoogleServicesFiles()
83+
{
84+
var googleServicesFiles = new List<string>();
85+
foreach (var asset in AssetDatabase.FindAssets(GoogleServicesFileBasename))
86+
{
87+
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
88+
if (Path.GetFileName(assetPath) == GoogleServicesInputFile)
89+
{
90+
googleServicesFiles.Add(assetPath);
91+
}
92+
}
93+
return googleServicesFiles.Count > 0 ? googleServicesFiles.ToArray() : null;
94+
}
95+
96+
static void UpdateJson()
97+
{
98+
#if UNITY_ANDROID
99+
var bundleId = ApplicationIdHelper.GetApplicationId();
100+
var projectDir = Path.Combine(Application.dataPath, "..");
101+
var googleServicesFiles = FindGoogleServicesFiles();
102+
if (googleServicesFiles == null)
103+
{
104+
return;
105+
}
106+
if (googleServicesFiles.Length > 1)
107+
{
108+
Debug.LogWarning("More than one " + GoogleServicesInputFile + " file found, using first one.");
109+
}
110+
var inputPath = Path.Combine(projectDir, googleServicesFiles[0]);
111+
var outputPath = Path.Combine(projectDir, GoogleServicesOutputPath);
112+
var outputDir = Path.Combine(projectDir, GoogleServicesOutputDirectory);
113+
if (!Directory.Exists(outputDir))
114+
{
115+
try
116+
{
117+
Directory.CreateDirectory(outputDir);
118+
}
119+
catch (Exception ex)
120+
{
121+
Debug.LogException(ex);
122+
return;
123+
}
124+
}
125+
if (File.Exists(outputPath) &&
126+
File.GetLastWriteTime(outputPath).CompareTo(File.GetLastWriteTime(inputPath)) >= 0)
127+
{
128+
return;
129+
}
130+
var json = File.ReadAllText(inputPath);
131+
var googleServices = JsonUtility.FromJson<GoogleServices>(json);
132+
var resolvedClientInfo = googleServices.GetClient(bundleId);
133+
if (resolvedClientInfo == null)
134+
{
135+
Debug.LogWarning("Failed to find client_info in " + GoogleServicesInputFile + " matching package name: " + bundleId);
136+
}
137+
var valuesItems = new Dictionary<string, string> {
138+
{ DefaultWebClientIdKey, googleServices.GetDefaultWebClientId(bundleId) },
139+
{ FirebaseDatabaseUrlKey, googleServices.GetFirebaseDatabaseUrl() },
140+
{ GATrackingIdKey, googleServices.GetGATrackingId(bundleId) },
141+
{ GSMDefaultSenderIdKey, googleServices.GetDefaultGcmSenderId() },
142+
{ GoogleAPIKey, googleServices.GetGoogleApiKey(bundleId) },
143+
{ GoogleAppIdKey, googleServices.GetGoogleAppId(bundleId) },
144+
{ CrashReportingApiKey, googleServices.GetCrashReportingApiKey(bundleId) },
145+
{ GoogleStorageBucketKey, googleServices.GetStorageBucket(bundleId) },
146+
{ ProjectIdKey, googleServices.GetProjectId() },
147+
};
148+
XmlResourceHelper.WriteXmlResource(outputPath, valuesItems);
149+
// Update editor project view.
150+
AssetDatabase.Refresh();
151+
#endif
152+
}
153+
154+
/// <summary>
155+
/// Handle delayed loading of the dependency resolvers.
156+
/// </summary>
157+
public static void SetupPush()
158+
{
159+
string[] importedAssets = AssetDatabase.GetAllAssetPaths();
160+
foreach (string asset in importedAssets)
161+
{
162+
if (asset.Contains("JarResolver"))
163+
{
164+
SetupDependencies();
165+
}
166+
else if (Path.GetFileName(asset) == GoogleServicesInputFile)
167+
{
168+
UpdateJson();
169+
}
170+
}
171+
}
172+
173+
#region Models
174+
175+
[Serializable]
176+
public class ProjectInfo
177+
{
178+
public string project_id;
179+
public string project_number;
180+
public string name;
181+
public string firebase_url;
182+
public string storage_bucket;
183+
}
184+
185+
[Serializable]
186+
public class AndroidClientInfo
187+
{
188+
public string package_name;
189+
public string[] certificate_hash;
190+
}
191+
192+
[Serializable]
193+
public class ClientInfo
194+
{
195+
public string mobilesdk_app_id;
196+
public string client_id;
197+
public int client_type;
198+
public AndroidClientInfo android_client_info;
199+
}
200+
201+
[Serializable]
202+
public class AndroidInfo
203+
{
204+
public string package_name;
205+
public string certificate_hash;
206+
}
207+
208+
[Serializable]
209+
public class OauthClient
210+
{
211+
public string client_id;
212+
public int client_type;
213+
public AndroidInfo android_info;
214+
}
215+
216+
[Serializable]
217+
public class AnalyticsProperty
218+
{
219+
public string tracking_id;
220+
}
221+
222+
[Serializable]
223+
public class AnalyticsService
224+
{
225+
public int status;
226+
public AnalyticsProperty analytics_property;
227+
}
228+
229+
[Serializable]
230+
public class Services
231+
{
232+
public AnalyticsService analytics_service;
233+
}
234+
235+
[Serializable]
236+
public class Client
237+
{
238+
public ClientInfo client_info;
239+
public OauthClient[] oauth_client;
240+
public ApiKey[] api_key;
241+
public Services services;
242+
}
243+
244+
[Serializable]
245+
public class ApiKey
246+
{
247+
public string current_key;
248+
}
249+
250+
[Serializable]
251+
public class GoogleServices
252+
{
253+
public ProjectInfo project_info;
254+
public Client[] client;
255+
public object[] client_info;
256+
public string ARTIFACT_VERSION;
257+
258+
public Client GetClient(string packageName)
259+
{
260+
if (client == null || !client.Any())
261+
return null;
262+
return client.FirstOrDefault(c => c.client_info.android_client_info.package_name == packageName);
263+
}
264+
265+
public string GetGATrackingId(string packageName)
266+
{
267+
// {YOUR_CLIENT}/services/analytics-service/analytics_property/tracking_id
268+
var client = GetClient(packageName);
269+
if (client == null)
270+
return null;
271+
if (client.services != null &&
272+
client.services.analytics_service != null &&
273+
client.services.analytics_service.analytics_property != null)
274+
return client.services.analytics_service.analytics_property.tracking_id;
275+
return null;
276+
}
277+
278+
public string GetProjectId()
279+
{
280+
// project_info/project_id
281+
if (project_info != null)
282+
return project_info.project_id;
283+
return null;
284+
}
285+
286+
public string GetDefaultGcmSenderId()
287+
{
288+
// project_info/project_number
289+
if (project_info != null)
290+
return project_info.project_number;
291+
return null;
292+
}
293+
294+
public string GetGoogleAppId(string packageName)
295+
{
296+
// {YOUR_CLIENT}/client_info/mobilesdk_app_id
297+
var client = GetClient(packageName);
298+
if (client == null)
299+
return null;
300+
if (client.client_info != null)
301+
return client.client_info.mobilesdk_app_id;
302+
return null;
303+
}
304+
305+
public string GetDefaultWebClientId(string packageName)
306+
{
307+
// default_web_client_id:
308+
// {YOUR_CLIENT}/oauth_client/client_id(client_type == 3)
309+
var client = GetClient(packageName);
310+
if (client == null)
311+
return null;
312+
if (client.oauth_client != null && client.oauth_client.Any())
313+
{
314+
var oauthClient = client.oauth_client.FirstOrDefault(c => c.client_type == 3);
315+
if (oauthClient != null)
316+
return oauthClient.client_id;
317+
}
318+
return null;
319+
}
320+
321+
public string GetGoogleApiKey(string packageName)
322+
{
323+
// google_api_key:
324+
// {YOUR_CLIENT}/api_key/current_key
325+
var client = GetClient(packageName);
326+
if (client == null)
327+
return null;
328+
if (client.api_key != null && client.api_key.Any())
329+
return client.api_key.FirstOrDefault().current_key;
330+
return null;
331+
}
332+
333+
public string GetFirebaseDatabaseUrl()
334+
{
335+
// firebase_database_url:
336+
// project_info/firebase_url
337+
if (project_info != null)
338+
return project_info.firebase_url;
339+
return null;
340+
}
341+
342+
public string GetCrashReportingApiKey(string packageName)
343+
{
344+
// google_crash_reporting_api_key:
345+
// {YOUR_CLIENT}/api_key/current_key
346+
var client = GetClient(packageName);
347+
if (client == null)
348+
return null;
349+
if (client.api_key != null && client.api_key.Any())
350+
return client.api_key.FirstOrDefault().current_key;
351+
return null;
352+
}
353+
354+
public string GetStorageBucket(string packageName)
355+
{
356+
// google_storage_bucket:
357+
// project_info/storage_bucket
358+
if (project_info != null)
359+
return project_info.storage_bucket;
360+
return null;
361+
}
362+
}
363+
364+
#endregion
365+
}

Assets/AppCenter/Editor/FirebaseDependency.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)