mobileBuild.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { exec } from 'node:child_process'
  2. import { promisify } from 'node:util'
  3. import path from 'node:path'
  4. import fs from 'node:fs'
  5. import { Listr } from 'listr2'
  6. import consola from 'consola'
  7. import { config } from 'dotenv'
  8. import { logLogo } from './logo'
  9. import { downloadFile } from './download'
  10. import { doesFileExist } from './fileExists'
  11. config()
  12. // yes | sdkmanager --sdk_root=/home/horanchikk/Documents/Sdk --licenses
  13. // sdkmanager --sdk_root=/home/horanchikk/Documents/Sdk --install "emulator" "build-tools;34.0.0" "build-tools;35.0.0" "platforms;android-34" "platform-tools"
  14. // export PATH=/home/horanchikk/Documents/jdk-20/bin:$PATH && ionic capacitor run android --list
  15. const execAsync = promisify(exec)
  16. const currentPath = path.resolve()
  17. async function runCommand(
  18. command: string,
  19. task?: {
  20. output: string
  21. },
  22. disableStdout: boolean | undefined = false,
  23. ) {
  24. try {
  25. const { stdout, stderr } = await execAsync(command)
  26. if (!disableStdout) {
  27. if (stderr) {
  28. if (task) {
  29. task.output = stderr
  30. }
  31. else { consola.log(stderr) }
  32. }
  33. else {
  34. if (task) {
  35. task.output = stdout
  36. }
  37. else { consola.log(stdout) }
  38. }
  39. }
  40. }
  41. catch (error) {
  42. if (!disableStdout) {
  43. if (task) {
  44. task.output = String(error)
  45. }
  46. else {
  47. consola.log(String(error))
  48. }
  49. }
  50. }
  51. }
  52. logLogo()
  53. const ANDROID_DEVICE_ID = process.env.ANDROID_DEVICE_ID
  54. const tools = ['emulator', 'build-tools;34.0.0', 'build-tools;35.0.0', 'platforms;android-34', 'platform-tools']
  55. let isSdkInstalled = true
  56. for (const tool of tools) {
  57. if (!doesFileExist(`./sdk/${tool.replace(';', '/')}/package.xml`)) {
  58. isSdkInstalled = false
  59. break
  60. }
  61. }
  62. try {
  63. await new Listr(
  64. [
  65. {
  66. title: 'Building nuxt',
  67. task: (_, task): Listr =>
  68. task.newListr(
  69. [
  70. {
  71. title: 'Removing old build',
  72. task: async (_) => {
  73. fs.rmSync('./.nuxt', { recursive: true, force: true })
  74. fs.rmSync('./.output', { recursive: true, force: true })
  75. },
  76. },
  77. {
  78. title: 'Re-building nuxt sources',
  79. task: async () => {
  80. await runCommand('nuxt generate', task)
  81. },
  82. },
  83. ],
  84. ),
  85. },
  86. {
  87. title: 'Building capacitor',
  88. task: (_, task): Listr =>
  89. task.newListr(
  90. [
  91. {
  92. title: 'Clearing old mobile builds',
  93. task: async (_) => {
  94. fs.rmSync('./android', { recursive: true, force: true })
  95. fs.rmSync('./ios', { recursive: true, force: true })
  96. },
  97. },
  98. {
  99. title: 'Adding mobile sources',
  100. task: async (_, task) => {
  101. await runCommand('npx cap add android', task)
  102. await runCommand('npx cap add ios', task)
  103. await runCommand('npx cap sync', task)
  104. },
  105. },
  106. ],
  107. ),
  108. },
  109. {
  110. title: `Android app`,
  111. task: (_, task): Listr =>
  112. task.newListr(
  113. [
  114. {
  115. title: 'Download Java SE 20',
  116. task: async (_, task) => {
  117. task.title = 'Checking java'
  118. if (!doesFileExist('./jdk/jdk-20/bin/java')) {
  119. await downloadFile(task, 'https://download.java.net/openjdk/jdk20/ri/openjdk-20+36_linux-x64_bin.tar.gz', 'jdk-20.tar.gz')
  120. task.title = 'Unzipping archive'
  121. await runCommand('rm -rf ./jdk && mkdir jdk && tar -xzf jdk-20.tar.gz -C jdk && rm jdk-20.tar.gz')
  122. task.title = 'Java installed'
  123. }
  124. else {
  125. task.title = 'Java already installed'
  126. }
  127. },
  128. },
  129. {
  130. title: 'Download Command Line Tools for Android',
  131. task: async (_, task) => {
  132. if (isSdkInstalled) {
  133. task.title = 'Command Line Tools already installed'
  134. }
  135. else {
  136. await downloadFile(task, 'https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip', 'cmdline-tools.zip')
  137. task.title = 'Unzipping archive'
  138. await runCommand('rm -rf ./cmdline-tools && unzip cmdline-tools.zip && rm cmdline-tools.zip')
  139. task.title = 'Command Line Tools successfully installed'
  140. }
  141. },
  142. },
  143. {
  144. title: 'Download additional tools for Android',
  145. task: async (_, task) => {
  146. if (isSdkInstalled) {
  147. task.title = 'Additional tools already installed'
  148. }
  149. else {
  150. task.title = 'While you using this application, you accepting all Android licenses'
  151. await runCommand(`yes | ./cmdline-tools/bin/sdkmanager --sdk_root=${currentPath}/sdk --licenses`)
  152. for (const tool of tools) {
  153. task.title = `Downloading ${tool}`
  154. await runCommand(`./cmdline-tools/bin/sdkmanager --sdk_root=${currentPath}/sdk --install "${tool}"`)
  155. }
  156. task.title = 'Additional tools successfully installed'
  157. }
  158. },
  159. },
  160. {
  161. title: `Setup local env ${!ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0 ? '[Will be skipped]' : ''}`,
  162. skip: !ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0,
  163. task: async (_, task) => {
  164. await runCommand(`export PATH=${currentPath}/jdk/jdk-20/bin:$PATH && export ANDROID_SDK_ROOT=${currentPath}/sdk`)
  165. task.title = 'ENV successfully setuped'
  166. },
  167. },
  168. {
  169. title: `Build android project ${!ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0 ? '[Will be skipped]' : ''}`,
  170. skip: !ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0,
  171. task: async (_, task) => {
  172. task.title = 'Gradle is building project, please wait'
  173. await runCommand('pnpm --package=@capacitor/cli dlx cap build android', task)
  174. task.title = 'Gradle building is finished'
  175. },
  176. },
  177. {
  178. title: `Run apk ${!ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0 ? '[Will be skipped]' : ''}`,
  179. skip: !ANDROID_DEVICE_ID || ANDROID_DEVICE_ID.length === 0,
  180. task: async (_, task) => {
  181. task.title = `Running app on device ${ANDROID_DEVICE_ID}`
  182. await runCommand(`pnpm --package=@capacitor/cli dlx cap run android --no-sync --target ${ANDROID_DEVICE_ID}`, task)
  183. task.title = `Launched at ${ANDROID_DEVICE_ID}`
  184. },
  185. },
  186. ],
  187. ),
  188. },
  189. ],
  190. { concurrent: false, rendererOptions: { collapseSubtasks: false } },
  191. ).run()
  192. }
  193. catch (e) {
  194. console.error(e)
  195. }