kotlin.ts 5.1 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import os from 'os'
fxy060608's avatar
fxy060608 已提交
2
import fs from 'fs-extra'
fxy060608's avatar
fxy060608 已提交
3
import path from 'path'
fxy060608's avatar
fxy060608 已提交
4 5
import AdmZip from 'adm-zip'
import { sync } from 'fast-glob'
fxy060608's avatar
fxy060608 已提交
6

fxy060608's avatar
fxy060608 已提交
7 8 9 10
import {
  installHBuilderXPlugin,
  isInHBuilderX,
  normalizePath,
fxy060608's avatar
fxy060608 已提交
11
  resolveSourceMapPath,
fxy060608's avatar
fxy060608 已提交
12
} from '@dcloudio/uni-cli-shared'
fxy060608's avatar
fxy060608 已提交
13 14 15 16
import {
  genUTSPlatformResource,
  getUtsCompiler,
  resolveAndroidDir,
fxy060608's avatar
fxy060608 已提交
17
  resolvePackage,
fxy060608's avatar
fxy060608 已提交
18 19 20 21
  resolveUTSPlatformFile,
  UTSPlatformResourceOptions,
} from './utils'

fxy060608's avatar
fxy060608 已提交
22 23 24 25
export function parseKotlinPackage(filename: string) {
  const res = resolvePackage(filename)
  if (!res) {
    return ''
fxy060608's avatar
fxy060608 已提交
26
  }
fxy060608's avatar
fxy060608 已提交
27
  return 'uts.sdk.' + (res.is_uni_modules ? 'modules.' : '') + res.name
fxy060608's avatar
fxy060608 已提交
28
}
fxy060608's avatar
fxy060608 已提交
29 30

export async function compileKotlin(filename: string) {
fxy060608's avatar
fxy060608 已提交
31 32 33 34 35 36
  if (!process.env.UNI_HBUILDERX_PLUGINS) {
    return
  }
  const { bundle, UtsTarget } = getUtsCompiler()
  const inputDir = process.env.UNI_INPUT_DIR
  const outputDir = process.env.UNI_OUTPUT_DIR
fxy060608's avatar
fxy060608 已提交
37
  // let time = Date.now()
fxy060608's avatar
fxy060608 已提交
38 39
  await bundle({
    target: UtsTarget.KOTLIN,
fxy060608's avatar
fxy060608 已提交
40
    input: {
fxy060608's avatar
fxy060608 已提交
41 42
      root: inputDir,
      filename,
fxy060608's avatar
fxy060608 已提交
43 44
    },
    output: {
fxy060608's avatar
fxy060608 已提交
45
      outDir: outputDir,
fxy060608's avatar
fxy060608 已提交
46
      package: parseKotlinPackage(filename),
fxy060608's avatar
fxy060608 已提交
47
      sourceMap: resolveSourceMapPath(),
fxy060608's avatar
fxy060608 已提交
48
      extname: 'kt',
fxy060608's avatar
fxy060608 已提交
49 50 51 52 53 54 55
      imports: [
        'kotlinx.coroutines.async',
        'kotlinx.coroutines.CoroutineScope',
        'kotlinx.coroutines.Deferred',
        'kotlinx.coroutines.Dispatchers',
        'io.dcloud.uts.*',
      ],
fxy060608's avatar
fxy060608 已提交
56
      logFilename: true,
fxy060608's avatar
fxy060608 已提交
57
      noColor: isInHBuilderX(),
fxy060608's avatar
fxy060608 已提交
58 59
    },
  })
fxy060608's avatar
fxy060608 已提交
60
  // console.log('uts compile time: ' + (Date.now() - time) + 'ms')
fxy060608's avatar
fxy060608 已提交
61 62 63 64 65 66
  const utsPlatformOptions: UTSPlatformResourceOptions = {
    inputDir,
    outputDir,
    platform: 'app-android',
    extname: '.kt',
  }
fxy060608's avatar
fxy060608 已提交
67
  if (process.env.NODE_ENV === 'production') {
fxy060608's avatar
fxy060608 已提交
68
    genUTSPlatformResource(filename, utsPlatformOptions)
fxy060608's avatar
fxy060608 已提交
69
  } else if (process.env.NODE_ENV === 'development') {
fxy060608's avatar
fxy060608 已提交
70
    const kotlinFile = resolveUTSPlatformFile(filename, utsPlatformOptions)
fxy060608's avatar
fxy060608 已提交
71 72
    // 开发模式下,需要生成 dex
    if (fs.existsSync(kotlinFile)) {
fxy060608's avatar
fxy060608 已提交
73 74 75 76
      const compilerServer = getCompilerServer()
      if (!compilerServer) {
        return
      }
fxy060608's avatar
fxy060608 已提交
77
      const { getDefaultJar, getKotlincHome, compile } = compilerServer
fxy060608's avatar
fxy060608 已提交
78
      // time = Date.now()
fxy060608's avatar
fxy060608 已提交
79
      const jarFile = resolveJarPath(kotlinFile)
fxy060608's avatar
fxy060608 已提交
80 81 82
      const options = {
        kotlinc: resolveKotlincArgs(
          kotlinFile,
fxy060608's avatar
fxy060608 已提交
83
          getKotlincHome(),
fxy060608's avatar
fxy060608 已提交
84 85 86 87 88
          getDefaultJar().concat(resolveLibs(filename))
        ),
        d8: resolveD8Args(jarFile),
      }
      const res = await compile(options, process.env.UNI_INPUT_DIR)
fxy060608's avatar
fxy060608 已提交
89
      // console.log('dex compile time: ' + (Date.now() - time) + 'ms')
fxy060608's avatar
fxy060608 已提交
90
      if (res) {
fxy060608's avatar
fxy060608 已提交
91 92 93 94 95
        try {
          fs.unlinkSync(jarFile)
          // 短期内先不删除,方便排查问题
          // fs.unlinkSync(kotlinFile)
        } catch (e) {}
fxy060608's avatar
fxy060608 已提交
96 97 98 99
        const dexFile = resolveDexFile(jarFile)
        if (fs.existsSync(dexFile)) {
          return normalizePath(path.relative(outputDir, dexFile))
        }
fxy060608's avatar
fxy060608 已提交
100
      }
fxy060608's avatar
fxy060608 已提交
101 102
    }
  }
fxy060608's avatar
fxy060608 已提交
103
}
fxy060608's avatar
fxy060608 已提交
104

fxy060608's avatar
fxy060608 已提交
105
function resolveKotlincArgs(filename: string, kotlinc: string, jars: string[]) {
fxy060608's avatar
fxy060608 已提交
106 107 108 109 110 111 112
  return [
    filename,
    '-cp',
    resolveClassPath(jars),
    '-d',
    resolveJarPath(filename),
    '-kotlin-home',
fxy060608's avatar
fxy060608 已提交
113
    kotlinc,
fxy060608's avatar
fxy060608 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  ]
}

function resolveD8Args(filename: string) {
  return [
    filename,
    '--no-desugaring',
    '--min-api',
    '19',
    '--output',
    resolveDexPath(filename),
  ]
}

function resolveLibs(filename: string) {
fxy060608's avatar
fxy060608 已提交
129
  const libsPath = path.resolve(resolveAndroidDir(filename), 'libs')
fxy060608's avatar
fxy060608 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
  const libs: string[] = []
  if (fs.existsSync(libsPath)) {
    libs.push(...sync('*.jar', { cwd: libsPath, absolute: true }))
    const zips = sync('*.aar', { cwd: libsPath })
    zips.forEach((name) => {
      const outputPath = resolveAndroidArchiveOutputPath(name)
      if (!fs.existsSync(outputPath)) {
        // 解压
        const zip = new AdmZip(path.resolve(libsPath, name))
        zip.extractAllTo(outputPath, true)
      }
    })
    if (zips.length) {
      libs.push(
        ...sync('*/*.jar', {
          cwd: resolveAndroidArchiveOutputPath(),
          absolute: true,
        })
      )
    }
  }
  return libs
}

function resolveAndroidArchiveOutputPath(aar?: string) {
  return path.resolve(
    process.env.UNI_OUTPUT_DIR,
    '../.uts/aar',
    aar ? aar.replace('.aar', '') : ''
  )
}
fxy060608's avatar
fxy060608 已提交
161 162 163 164
function resolveDexFile(jarFile: string) {
  return normalizePath(path.resolve(path.dirname(jarFile), 'classes.dex'))
}

fxy060608's avatar
fxy060608 已提交
165 166 167 168 169 170 171 172
function resolveDexPath(filename: string) {
  return path.dirname(filename)
}

function resolveJarPath(filename: string) {
  return filename.replace(path.extname(filename), '.jar')
}

fxy060608's avatar
fxy060608 已提交
173 174
function resolveClassPath(jars: string[]) {
  return jars.join(os.platform() === 'win32' ? ';' : ':')
fxy060608's avatar
fxy060608 已提交
175 176
}

fxy060608's avatar
fxy060608 已提交
177 178
const getCompilerServer = ():
  | {
fxy060608's avatar
fxy060608 已提交
179
      getKotlincHome(): string
fxy060608's avatar
fxy060608 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
      getDefaultJar(): string[]
      compile(
        options: { kotlinc: string[]; d8: string[] },
        projectPath: string
      ): Promise<boolean>
    }
  | false => {
  try {
    const compilerServerPath = path.resolve(
      process.env.UNI_HBUILDERX_PLUGINS,
      'uniapp-runextension/out/main.js'
    )
    // eslint-disable-next-line no-restricted-globals
    return require(compilerServerPath)
  } catch (e) {
    installHBuilderXPlugin('uniapp-runextension')
fxy060608's avatar
fxy060608 已提交
196
  }
fxy060608's avatar
fxy060608 已提交
197 198
  return false
}