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  `