BuildAndroid.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  2. // Please see LICENSE.md in repository root for license information
  3. // https://github.com/AtomicGameEngine/AtomicGameEngine
  4. #include <Atomic/Core/StringUtils.h>
  5. #include <Atomic/IO/FileSystem.h>
  6. #include <Atomic/IO/File.h>
  7. #include <Atomic/IO/MemoryBuffer.h>
  8. #include "../ToolSystem.h"
  9. #include "../ToolEnvironment.h"
  10. #include "../Subprocess/SubprocessSystem.h"
  11. #include "../Project/Project.h"
  12. #include "../Project/ProjectBuildSettings.h"
  13. #include "../Platform/PlatformAndroid.h"
  14. #include "AndroidProjectGenerator.h"
  15. #include "BuildSystem.h"
  16. #include "BuildEvents.h"
  17. #include "BuildAndroid.h"
  18. namespace ToolCore
  19. {
  20. BuildAndroid::BuildAndroid(Context* context, Project* project) : BuildBase(context, project)
  21. {
  22. ToolSystem* toolSystem = GetSubsystem<ToolSystem>();
  23. // this cast isn't great
  24. platformAndroid_ = (PlatformAndroid*) toolSystem->GetPlatformByID(PLATFORMID_ANDROID);
  25. }
  26. BuildAndroid::~BuildAndroid()
  27. {
  28. }
  29. void BuildAndroid::SendBuildFailure(const String& message)
  30. {
  31. VariantMap buildError;
  32. buildError[BuildFailed::P_PLATFORMID] = PLATFORMID_ANDROID;
  33. buildError[BuildFailed::P_MESSAGE] = message;
  34. SendEvent(E_BUILDFAILED, buildError);
  35. }
  36. void BuildAndroid::HandleADBStartActivityComplete(StringHash eventType, VariantMap& eventData)
  37. {
  38. }
  39. // adb shell am start -n com.package.name/com.package.name.ActivityName
  40. void BuildAndroid::RunADBStartActivity()
  41. {
  42. SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
  43. String adbCommand = platformAndroid_->GetADBCommand();
  44. ToolSystem* toolSystem = GetSubsystem<ToolSystem>();
  45. Project* project = toolSystem->GetProject();
  46. AndroidBuildSettings* settings = project->GetBuildSettings()->GetAndroidBuildSettings();
  47. String stringArgs;
  48. const char* cpackage = settings->GetPackageName().CString();
  49. stringArgs.AppendWithFormat("shell am start -n %s/%s.AtomicGameEngine",cpackage, cpackage);
  50. Vector<String> args = stringArgs.Split(' ');
  51. currentBuildPhase_ = ADBStartActivity;
  52. Subprocess* subprocess = subs->Launch(adbCommand, args, buildPath_);
  53. if (!subprocess)
  54. {
  55. SendBuildFailure("BuildFailed::RunStartActivity");
  56. return;
  57. }
  58. VariantMap buildOutput;
  59. buildOutput[BuildOutput::P_TEXT] = "\n\n<color #D4FB79>Starting Android Activity</color>\n\n";
  60. SendEvent(E_BUILDOUTPUT, buildOutput);
  61. SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildAndroid, HandleADBStartActivityComplete));
  62. SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildBase, HandleSubprocessOutputEvent));
  63. }
  64. void BuildAndroid::HandleRunADBInstallComplete(StringHash eventType, VariantMap& eventData)
  65. {
  66. int code = eventData[SubprocessComplete::P_RETCODE].GetInt();
  67. if (!code)
  68. {
  69. RunADBStartActivity();
  70. }
  71. else
  72. {
  73. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  74. buildSystem->BuildComplete(PLATFORMID_ANDROID, buildPath_, false);
  75. }
  76. }
  77. void BuildAndroid::RunADBInstall()
  78. {
  79. SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
  80. String adbCommand = platformAndroid_->GetADBCommand();
  81. Vector<String> args = String("install -r ./bin/Atomic-debug-unaligned.apk").Split(' ');
  82. currentBuildPhase_ = ADBInstall;
  83. Subprocess* subprocess = subs->Launch(adbCommand, args, buildPath_);
  84. if (!subprocess)
  85. {
  86. SendBuildFailure("BuildFailed::RunADBInstall");
  87. return;
  88. }
  89. VariantMap buildOutput;
  90. buildOutput[BuildOutput::P_TEXT] = "\n\n<color #D4FB79>Installing on Android Device</color>\n\n";
  91. SendEvent(E_BUILDOUTPUT, buildOutput);
  92. SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildAndroid, HandleRunADBInstallComplete));
  93. SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildBase, HandleSubprocessOutputEvent));
  94. }
  95. void BuildAndroid::HandleADBListDevicesComplete(StringHash eventType, VariantMap& eventData)
  96. {
  97. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  98. int code = eventData[SubprocessComplete::P_RETCODE].GetInt();
  99. if (!code)
  100. {
  101. // check if we have any devices attached, otherwise adb install
  102. // will hang looking for devices
  103. bool noDevices = true;
  104. if (deviceListText_.Length())
  105. {
  106. MemoryBuffer reader(deviceListText_.CString(), deviceListText_.Length() + 1);
  107. while (!reader.IsEof())
  108. {
  109. String line = reader.ReadLine();
  110. if (line.Length() && line[0] >= '0' && line[0] <= '9')
  111. {
  112. noDevices = false;
  113. break;
  114. }
  115. }
  116. }
  117. if (!noDevices)
  118. RunADBInstall();
  119. else
  120. {
  121. // can't proceed, though success
  122. buildSystem->BuildComplete(PLATFORMID_ANDROID, buildPath_);
  123. }
  124. }
  125. else
  126. {
  127. buildSystem->BuildComplete(PLATFORMID_ANDROID, buildPath_, false);
  128. }
  129. }
  130. void BuildAndroid::HandleADBListDevicesOutputEvent(StringHash eventType, VariantMap& eventData)
  131. {
  132. // E_SUBPROCESSOUTPUT
  133. const String& text = eventData[SubprocessOutput::P_TEXT].GetString();
  134. deviceListText_ += text;
  135. // convert to a build output event and forward to subscribers
  136. VariantMap buildOutputData;
  137. buildOutputData[BuildOutput::P_TEXT] = text;
  138. SendEvent(E_BUILDOUTPUT, buildOutputData);
  139. }
  140. void BuildAndroid::RunADBListDevices()
  141. {
  142. ToolSystem* toolSystem = GetSubsystem<ToolSystem>();
  143. SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
  144. String adbCommand = platformAndroid_->GetADBCommand();
  145. deviceListText_.Clear();
  146. Vector<String> args = String("devices").Split(' ');
  147. currentBuildPhase_ = ADBListDevices;
  148. Subprocess* subprocess = subs->Launch(adbCommand, args, "");
  149. if (!subprocess)
  150. {
  151. SendBuildFailure("BuildFailed::RunADBListDevices");
  152. return;
  153. }
  154. VariantMap buildOutput;
  155. buildOutput[BuildOutput::P_TEXT] = "\n\n<color #D4FB79>Listing Android Devices</color>\n\n";
  156. SendEvent(E_BUILDOUTPUT, buildOutput);
  157. SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildAndroid, HandleADBListDevicesComplete));
  158. SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildAndroid, HandleADBListDevicesOutputEvent));
  159. }
  160. void BuildAndroid::HandleAntDebugComplete(StringHash eventType, VariantMap& eventData)
  161. {
  162. int code = eventData[SubprocessComplete::P_RETCODE].GetInt();
  163. if (!code)
  164. {
  165. RunADBListDevices();
  166. }
  167. else
  168. {
  169. BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  170. buildSystem->BuildComplete(PLATFORMID_ANDROID, buildPath_, false);
  171. }
  172. }
  173. void BuildAndroid::RunAntDebug()
  174. {
  175. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  176. SubprocessSystem* subs = GetSubsystem<SubprocessSystem>();
  177. ToolPrefs* tprefs = tenv->GetToolPrefs();
  178. Poco::Process::Env env;
  179. #ifdef ATOMIC_PLATFORM_OSX
  180. String antCommand = tprefs->GetAntPath();
  181. Vector<String> args;
  182. args.Push("debug");
  183. #else
  184. // C:\ProgramData\Oracle\Java\javapath;
  185. Vector<String> args;
  186. String antCommand = "cmd";
  187. String antPath = prefs->GetAntPath() + "/ant.bat";
  188. env["JAVA_HOME"] = prefs->GetJDKRootPath().CString();
  189. // ant is a batch file on windows, so have to run with cmd /c
  190. args.Push("/c");
  191. args.Push("\"" + antPath + "\"");
  192. args.Push("debug");
  193. #endif
  194. currentBuildPhase_ = AntBuildDebug;
  195. Subprocess* subprocess = subs->Launch(antCommand, args, buildPath_, env);
  196. if (!subprocess)
  197. {
  198. SendBuildFailure("BuildFailed::RunAntDebug");
  199. return;
  200. }
  201. VariantMap buildOutput;
  202. buildOutput[BuildOutput::P_TEXT] = "<color #D4FB79>Starting Android Deployment</color>\n\n";
  203. SendEvent(E_BUILDOUTPUT, buildOutput);
  204. SubscribeToEvent(subprocess, E_SUBPROCESSCOMPLETE, HANDLER(BuildAndroid, HandleAntDebugComplete));
  205. SubscribeToEvent(subprocess, E_SUBPROCESSOUTPUT, HANDLER(BuildBase, HandleSubprocessOutputEvent));
  206. }
  207. void BuildAndroid::Initialize()
  208. {
  209. ToolSystem* tsystem = GetSubsystem<ToolSystem>();
  210. Project* project = tsystem->GetProject();
  211. Vector<String> defaultResourcePaths;
  212. GetDefaultResourcePaths(defaultResourcePaths);
  213. String projectResources = project->GetResourcePath();
  214. for (unsigned i = 0; i < defaultResourcePaths.Size(); i++)
  215. {
  216. AddResourceDir(defaultResourcePaths[i]);
  217. }
  218. // TODO: smart filtering of cache
  219. AddResourceDir(project->GetProjectPath() + "Cache/");
  220. AddResourceDir(projectResources);
  221. BuildResourceEntries();
  222. }
  223. void BuildAndroid::Build(const String& buildPath)
  224. {
  225. ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
  226. ToolSystem* tsystem = GetSubsystem<ToolSystem>();
  227. Project* project = tsystem->GetProject();
  228. buildPath_ = AddTrailingSlash(buildPath) + GetBuildSubfolder();
  229. Initialize();
  230. //generate manifest file
  231. String manifest;
  232. for (unsigned i = 0; i < resourceEntries_.Size(); i++)
  233. {
  234. BuildResourceEntry* entry = resourceEntries_[i];
  235. manifest += entry->packagePath_;
  236. if ( i != resourceEntries_.Size() - 1)
  237. manifest += ";";
  238. }
  239. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  240. if (fileSystem->DirExists(buildPath_))
  241. fileSystem->RemoveDir(buildPath_, true);
  242. String buildSourceDir = tenv->GetToolDataDir();
  243. String androidProject = buildSourceDir + "Deployment/Android";
  244. // Copy the base android project
  245. fileSystem->CopyDir(androidProject, buildPath_);
  246. Vector<String> defaultResourcePaths;
  247. GetDefaultResourcePaths(defaultResourcePaths);
  248. String projectResources = project->GetResourcePath();
  249. for (unsigned i = 0; i < defaultResourcePaths.Size(); i++)
  250. {
  251. fileSystem->CopyDir(defaultResourcePaths[i], buildPath_ + "/assets/" + GetFileName(RemoveTrailingSlash(defaultResourcePaths[i])));
  252. }
  253. fileSystem->CopyDir(project->GetProjectPath() + "Cache/", buildPath_ + "/assets/Cache");
  254. fileSystem->CopyDir(projectResources, buildPath_ + "/assets/AtomicResources");
  255. // write the manifest
  256. SharedPtr<File> mfile(new File(context_, buildPath_ + "/assets/AtomicManifest", FILE_WRITE));
  257. mfile->WriteString(manifest);
  258. mfile->Close();
  259. AndroidProjectGenerator gen(context_);
  260. gen.SetBuildPath(buildPath_);
  261. if (!gen.Generate())
  262. {
  263. SendBuildFailure(gen.GetErrorText());
  264. return;
  265. }
  266. RunAntDebug();
  267. //BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
  268. //buildSystem->BuildComplete(PLATFORMID_ANDROID, buildPath_);
  269. //fileSystem->SystemCommandAsync("/Applications/Firefox.app/Contents/MacOS/firefox");
  270. }
  271. }