github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/cmd/gomobile/build_androidapp.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "bytes" 9 "crypto/x509" 10 //"encoding/base64" 11 "encoding/pem" 12 "errors" 13 "fmt" 14 "go/build" 15 "io" 16 "io/ioutil" 17 //"log" 18 "os" 19 "path" 20 "path/filepath" 21 "strings" 22 ) 23 24 func goAndroidBuild(pkg *build.Package) (map[string]bool, error) { 25 fmt.Println("goAndroidBuild") 26 libName := path.Base(pkg.ImportPath) 27 manifestPath := filepath.Join(pkg.Dir, "AndroidManifest.xml") 28 manifestData, err := ioutil.ReadFile(manifestPath) 29 30 fmt.Printf("manifestData 000 %s", manifestData) 31 32 if err != nil { 33 if !os.IsNotExist(err) { 34 return nil, err 35 } 36 37 productName := rfc1034Label(libName) 38 if productName == "" { 39 productName = "ProductName" // like xcode. 40 } 41 42 buf := new(bytes.Buffer) 43 buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`) 44 err := manifestTmpl.Execute(buf, manifestTmplData{ 45 // TODO(crawshaw): a better package path. 46 JavaPkgPath: "org.golang.todo." + productName, 47 Name: libName, 48 LibName: libName, 49 }) 50 if err != nil { 51 return nil, err 52 } 53 manifestData = buf.Bytes() 54 55 fmt.Printf("manifestData 0 %s", manifestData) 56 57 if buildV { 58 fmt.Fprintf(os.Stderr, "generated AndroidManifest.xml:\n%s\n", manifestData) 59 } 60 } else { 61 libName, err = manifestLibName(manifestData) 62 if err != nil { 63 return nil, fmt.Errorf("error parsing %s: %v", manifestPath, err) 64 } 65 } 66 libPath := filepath.Join(tmpdir, "lib"+libName+".so") 67 68 err = goBuild( 69 pkg.ImportPath, 70 androidArmEnv, 71 "-buildmode=c-shared", 72 "-o", libPath, 73 ) 74 if err != nil { 75 return nil, err 76 } 77 78 nmpkgs, err := extractPkgs(androidArmNM, libPath) 79 if err != nil { 80 return nil, err 81 } 82 83 block, _ := pem.Decode([]byte(debugCert)) 84 if block == nil { 85 return nil, errors.New("no debug cert") 86 } 87 privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) 88 if err != nil { 89 return nil, err 90 } 91 92 if buildO == "" { 93 buildO = filepath.Base(pkg.Dir) + ".apk" 94 } 95 if !strings.HasSuffix(buildO, ".apk") { 96 return nil, fmt.Errorf("output file name %q does not end in '.apk'", buildO) 97 } 98 var out io.Writer 99 if !buildN { 100 f, err := os.Create(buildO) 101 if err != nil { 102 return nil, err 103 } 104 defer func() { 105 if cerr := f.Close(); err == nil { 106 err = cerr 107 } 108 }() 109 out = f 110 } 111 112 var apkw *Writer 113 if !buildN { 114 apkw = NewWriter(out, privKey) 115 } 116 apkwcreate := func(name string) (io.Writer, error) { 117 if buildV { 118 fmt.Fprintf(os.Stderr, "apk: %s\n", name) 119 } 120 if buildN { 121 return ioutil.Discard, nil 122 } 123 return apkw.Create(name) 124 } 125 126 fmt.Printf("manifestData %s", manifestData) 127 w, err := apkwcreate("AndroidManifest.xml") 128 if err != nil { 129 return nil, err 130 } 131 if _, err := w.Write(manifestData); err != nil { 132 return nil, err 133 } 134 135 w, err = apkwcreate("classes.dex") 136 if err != nil { 137 return nil, err 138 } 139 /*dexData, err := base64.StdEncoding.DecodeString(dexStr) 140 if err != nil { 141 log.Fatal("internal error bad dexStr: %v", err) 142 } 143 */ 144 dexData, _ := ioutil.ReadFile("/home/z/go-projects/src/github.com/democratic-coin/dcoin-go/classes.dex") 145 if _, err := w.Write(dexData); err != nil { 146 return nil, err 147 } 148 149 w, err = apkwcreate("lib/armeabi/lib" + libName + ".so") 150 if err != nil { 151 return nil, err 152 } 153 if !buildN { 154 r, err := os.Open(libPath) 155 if err != nil { 156 return nil, err 157 } 158 if _, err := io.Copy(w, r); err != nil { 159 return nil, err 160 } 161 } 162 163 if nmpkgs["github.com/democratic-coin/dcoin-go/vendor/src/golang.org/x/mobile/exp/audio/al"] { 164 alDir := filepath.Join(ndkccpath, "openal/lib") 165 filepath.Walk(alDir, func(path string, info os.FileInfo, err error) error { 166 if err != nil { 167 return err 168 } 169 if info.IsDir() { 170 return nil 171 } 172 name := "lib/" + path[len(alDir)+1:] 173 w, err := apkwcreate(name) 174 if err != nil { 175 return err 176 } 177 if !buildN { 178 f, err := os.Open(path) 179 if err != nil { 180 return err 181 } 182 defer f.Close() 183 _, err = io.Copy(w, f) 184 } 185 return err 186 }) 187 } 188 189 // Add any assets. 190 assetsDir := filepath.Join(pkg.Dir, "assets") 191 assetsDirExists := true 192 fi, err := os.Stat(assetsDir) 193 if err != nil { 194 if os.IsNotExist(err) { 195 assetsDirExists = false 196 } else { 197 return nil, err 198 } 199 } else { 200 assetsDirExists = fi.IsDir() 201 } 202 if assetsDirExists { 203 err = filepath.Walk(assetsDir, func(path string, info os.FileInfo, err error) error { 204 if err != nil { 205 return err 206 } 207 if info.IsDir() { 208 return nil 209 } 210 name := "assets/" + path[len(assetsDir)+1:] 211 w, err := apkwcreate(name) 212 if err != nil { 213 return err 214 } 215 f, err := os.Open(path) 216 if err != nil { 217 return err 218 } 219 defer f.Close() 220 _, err = io.Copy(w, f) 221 return err 222 }) 223 if err != nil { 224 return nil, fmt.Errorf("asset %v", err) 225 } 226 } 227 228 229 230 231 // Add any res. 232 resDir := filepath.Join(pkg.Dir, "res") 233 resDirExists := true 234 fi, err = os.Stat(resDir) 235 if err != nil { 236 if os.IsNotExist(err) { 237 resDirExists = false 238 } else { 239 return nil, err 240 } 241 } else { 242 resDirExists = fi.IsDir() 243 } 244 if resDirExists { 245 err = filepath.Walk(resDir, func(path string, info os.FileInfo, err error) error { 246 if err != nil { 247 return err 248 } 249 if info.IsDir() { 250 return nil 251 } 252 name := "res/" + path[len(resDir)+1:] 253 w, err := apkwcreate(name) 254 if err != nil { 255 return err 256 } 257 f, err := os.Open(path) 258 if err != nil { 259 return err 260 } 261 defer f.Close() 262 _, err = io.Copy(w, f) 263 return err 264 }) 265 if err != nil { 266 return nil, fmt.Errorf("res %v", err) 267 } 268 } 269 270 271 272 273 // Add any lib. 274 libDir := filepath.Join(pkg.Dir, "lib") 275 libDirExists := true 276 fi, err = os.Stat(libDir) 277 if err != nil { 278 if os.IsNotExist(err) { 279 libDirExists = false 280 } else { 281 return nil, err 282 } 283 } else { 284 libDirExists = fi.IsDir() 285 } 286 if libDirExists { 287 err = filepath.Walk(libDir, func(path string, info os.FileInfo, err error) error { 288 if err != nil { 289 return err 290 } 291 if info.IsDir() { 292 return nil 293 } 294 name := "lib/" + path[len(libDir)+1:] 295 w, err := apkwcreate(name) 296 if err != nil { 297 return err 298 } 299 f, err := os.Open(path) 300 if err != nil { 301 return err 302 } 303 defer f.Close() 304 _, err = io.Copy(w, f) 305 return err 306 }) 307 if err != nil { 308 return nil, fmt.Errorf("lib %v", err) 309 } 310 } 311 312 name := "resources.arsc" 313 resPath := filepath.Join(pkg.Dir, name) 314 w, err = apkwcreate(name) 315 if err != nil { 316 return nil, err 317 } 318 f, err := os.Open(resPath) 319 if err != nil { 320 return nil, err 321 } 322 defer f.Close() 323 _, err = io.Copy(w, f) 324 if err != nil { 325 return nil, err 326 } 327 328 329 // TODO: add gdbserver to apk? 330 331 if !buildN { 332 if err := apkw.Close(); err != nil { 333 return nil, err 334 } 335 } 336 337 return nmpkgs, nil 338 } 339 340 // A random uninteresting private key. 341 // Must be consistent across builds so newer app versions can be installed. 342 const debugCert = ` 343 -----BEGIN RSA PRIVATE KEY----- 344 MIIEowIBAAKCAQEAy6ItnWZJ8DpX9R5FdWbS9Kr1U8Z7mKgqNByGU7No99JUnmyu 345 NQ6Uy6Nj0Gz3o3c0BXESECblOC13WdzjsH1Pi7/L9QV8jXOXX8cvkG5SJAyj6hcO 346 LOapjDiN89NXjXtyv206JWYvRtpexyVrmHJgRAw3fiFI+m4g4Qop1CxcIF/EgYh7 347 rYrqh4wbCM1OGaCleQWaOCXxZGm+J5YNKQcWpjZRrDrb35IZmlT0bK46CXUKvCqK 348 x7YXHgfhC8ZsXCtsScKJVHs7gEsNxz7A0XoibFw6DoxtjKzUCktnT0w3wxdY7OTj 349 9AR8mobFlM9W3yirX8TtwekWhDNTYEu8dwwykwIDAQABAoIBAA2hjpIhvcNR9H9Z 350 BmdEecydAQ0ZlT5zy1dvrWI++UDVmIp+Ve8BSd6T0mOqV61elmHi3sWsBN4M1Rdz 351 3N38lW2SajG9q0fAvBpSOBHgAKmfGv3Ziz5gNmtHgeEXfZ3f7J95zVGhlHqWtY95 352 JsmuplkHxFMyITN6WcMWrhQg4A3enKLhJLlaGLJf9PeBrvVxHR1/txrfENd2iJBH 353 FmxVGILL09fIIktJvoScbzVOneeWXj5vJGzWVhB17DHBbANGvVPdD5f+k/s5aooh 354 hWAy/yLKocr294C4J+gkO5h2zjjjSGcmVHfrhlXQoEPX+iW1TGoF8BMtl4Llc+jw 355 lKWKfpECgYEA9C428Z6CvAn+KJ2yhbAtuRo41kkOVoiQPtlPeRYs91Pq4+NBlfKO 356 2nWLkyavVrLx4YQeCeaEU2Xoieo9msfLZGTVxgRlztylOUR+zz2FzDBYGicuUD3s 357 EqC0Wv7tiX6dumpWyOcVVLmR9aKlOUzA9xemzIsWUwL3PpyONhKSq7kCgYEA1X2F 358 f2jKjoOVzglhtuX4/SP9GxS4gRf9rOQ1Q8DzZhyH2LZ6Dnb1uEQvGhiqJTU8CXxb 359 7odI0fgyNXq425Nlxc1Tu0G38TtJhwrx7HWHuFcbI/QpRtDYLWil8Zr7Q3BT9rdh 360 moo4m937hLMvqOG9pyIbyjOEPK2WBCtKW5yabqsCgYEAu9DkUBr1Qf+Jr+IEU9I8 361 iRkDSMeusJ6gHMd32pJVCfRRQvIlG1oTyTMKpafmzBAd/rFpjYHynFdRcutqcShm 362 aJUq3QG68U9EAvWNeIhA5tr0mUEz3WKTt4xGzYsyWES8u4tZr3QXMzD9dOuinJ1N 363 +4EEumXtSPKKDG3M8Qh+KnkCgYBUEVSTYmF5EynXc2xOCGsuy5AsrNEmzJqxDUBI 364 SN/P0uZPmTOhJIkIIZlmrlW5xye4GIde+1jajeC/nG7U0EsgRAV31J4pWQ5QJigz 365 0+g419wxIUFryGuIHhBSfpP472+w1G+T2mAGSLh1fdYDq7jx6oWE7xpghn5vb9id 366 EKLjdwKBgBtz9mzbzutIfAW0Y8F23T60nKvQ0gibE92rnUbjPnw8HjL3AZLU05N+ 367 cSL5bhq0N5XHK77sscxW9vXjG0LJMXmFZPp9F6aV6ejkMIXyJ/Yz/EqeaJFwilTq 368 Mc6xR47qkdzu0dQ1aPm4XD7AWDtIvPo/GG2DKOucLBbQc2cOWtKS 369 -----END RSA PRIVATE KEY----- 370 `