Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b39ed68

Browse files
committed
cmd/gomobile: sanitize android app package names
https://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html "This can occur if the domain name contains a hyphen or other special character, if the package name begins with a digit or other character that is illegal to use as the beginning of a Java name, or if the package name contains a reserved Java keyword, such as "int". In this event, the suggested convention is to add an underscore." The sanitized name is used for the app package name and the default apk file name. Update golang/go#12273 Change-Id: I76d7f423e87c54a5bb7ab71ec251fd3a26da9722 Reviewed-on: https://go-review.googlesource.com/16875 Reviewed-by: David Crawshaw <[email protected]>
1 parent d95efb4 commit b39ed68

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

cmd/gomobile/build_androidapp.go

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,21 @@ import (
2222
)
2323

2424
func goAndroidBuild(pkg *build.Package) (map[string]bool, error) {
25-
libName := path.Base(pkg.ImportPath)
25+
appName := path.Base(pkg.ImportPath)
26+
libName := androidPkgName(appName)
2627
manifestPath := filepath.Join(pkg.Dir, "AndroidManifest.xml")
2728
manifestData, err := ioutil.ReadFile(manifestPath)
2829
if err != nil {
2930
if !os.IsNotExist(err) {
3031
return nil, err
3132
}
3233

33-
productName := rfc1034Label(libName)
34-
if productName == "" {
35-
productName = "ProductName" // like xcode.
36-
}
37-
3834
buf := new(bytes.Buffer)
3935
buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
4036
err := manifestTmpl.Execute(buf, manifestTmplData{
4137
// TODO(crawshaw): a better package path.
42-
JavaPkgPath: "org.golang.todo." + productName,
43-
Name: strings.Title(libName),
38+
JavaPkgPath: "org.golang.todo." + libName,
39+
Name: strings.Title(appName),
4440
LibName: libName,
4541
})
4642
if err != nil {
@@ -83,7 +79,7 @@ func goAndroidBuild(pkg *build.Package) (map[string]bool, error) {
8379
}
8480

8581
if buildO == "" {
86-
buildO = filepath.Base(pkg.Dir) + ".apk"
82+
buildO = androidPkgName(filepath.Base(pkg.Dir)) + ".apk"
8783
}
8884
if !strings.HasSuffix(buildO, ".apk") {
8985
return nil, fmt.Errorf("output file name %q does not end in '.apk'", buildO)
@@ -214,6 +210,51 @@ func goAndroidBuild(pkg *build.Package) (map[string]bool, error) {
214210
return nmpkgs, nil
215211
}
216212

213+
// androidPkgName sanitizes the go package name to be acceptable as a android
214+
// package name part. The android package name convention is similar to the
215+
// java package name convention described in
216+
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.5.3.1
217+
// but not exactly same.
218+
func androidPkgName(name string) string {
219+
var res []rune
220+
for i, r := range name {
221+
switch {
222+
case 'a' <= r && r <= 'z', 'A' <= r && r <= 'Z':
223+
res = append(res, r)
224+
case '0' <= r && r <= '9':
225+
if i == 0 {
226+
panic(fmt.Sprintf("package name %q is not a valid go package name", name))
227+
}
228+
res = append(res, r)
229+
default:
230+
res = append(res, '_')
231+
}
232+
}
233+
if len(res) == 0 || res[0] == '_' {
234+
// Android does not seem to allow the package part starting with _.
235+
res = append([]rune{'g', 'o'}, res...)
236+
}
237+
s := string(res)
238+
// Look for Java keywords that are not Go keywords, and avoid using
239+
// them as a package name.
240+
//
241+
// This is not a problem for normal Go identifiers as we only expose
242+
// exported symbols. The upper case first letter saves everything
243+
// from accidentally matching except for the package name.
244+
//
245+
// Note that basic type names (like int) are not keywords in Go.
246+
switch s {
247+
case "abstract", "assert", "boolean", "byte", "catch", "char", "class",
248+
"do", "double", "enum", "extends", "final", "finally", "float",
249+
"implements", "instanceof", "int", "long", "native", "private",
250+
"protected", "public", "short", "static", "strictfp", "super",
251+
"synchronized", "this", "throw", "throws", "transient", "try",
252+
"void", "volatile", "while":
253+
s += "_"
254+
}
255+
return s
256+
}
257+
217258
// A random uninteresting private key.
218259
// Must be consistent across builds so newer app versions can be installed.
219260
const debugCert = `

cmd/gomobile/build_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,33 @@ func TestRFC1034Label(t *testing.T) {
3636
}
3737
}
3838

39+
func TestAndroidPkgName(t *testing.T) {
40+
tests := []struct {
41+
in, want string
42+
}{
43+
{"a", "a"},
44+
{"a123", "a123"},
45+
{"a.b.c", "a_b_c"},
46+
{"a-b", "a_b"},
47+
{"a:b", "a_b"},
48+
{"a?b", "a_b"},
49+
{"αβγ", "go___"},
50+
{"💩", "go_"},
51+
{"My App", "My_App"},
52+
{"...", "go___"},
53+
{".-.", "go___"},
54+
{"abstract", "abstract_"},
55+
{"Abstract", "Abstract"},
56+
}
57+
58+
for _, tc := range tests {
59+
if got := androidPkgName(tc.in); got != tc.want {
60+
t.Errorf("len %d", len(tc.in))
61+
t.Errorf("androidPkgName(%q) = %q, want %q", tc.in, got, tc.want)
62+
}
63+
}
64+
}
65+
3966
func TestAndroidBuild(t *testing.T) {
4067
buf := new(bytes.Buffer)
4168
defer func() {

cmd/gomobile/install.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func runInstall(cmd *command) error {
4242
`adb`,
4343
`install`,
4444
`-r`,
45-
filepath.Base(pkg.Dir)+`.apk`,
45+
androidPkgName(filepath.Base(pkg.Dir))+`.apk`,
4646
)
4747
c.Stdout = os.Stdout
4848
c.Stderr = os.Stderr

0 commit comments

Comments
 (0)