first commit

This commit is contained in:
2024-07-23 10:23:43 +08:00
commit 7b4c2521a3
126 changed files with 15931 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
package apk
import (
"archive/zip"
"bytes"
"fmt"
"git.bvbej.com/bvbej/base-golang/pkg/android_binary"
"image"
"io"
"os"
"strconv"
_ "image/jpeg" // handle jpeg format
_ "image/png" // handle png format
)
// Apk is an application package file for android.
type Apk struct {
f *os.File
zipreader *zip.Reader
manifest Manifest
table *android_binary.TableFile
}
// OpenFile will open the file specified by filename and return Apk
func OpenFile(filename string) (apk *Apk, err error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer func() {
if err != nil {
f.Close()
}
}()
fi, err := f.Stat()
if err != nil {
return nil, err
}
apk, err = OpenZipReader(f, fi.Size())
if err != nil {
return nil, err
}
apk.f = f
return
}
// OpenZipReader has same arguments like zip.NewReader
func OpenZipReader(r io.ReaderAt, size int64) (*Apk, error) {
zipreader, err := zip.NewReader(r, size)
if err != nil {
return nil, err
}
apk := &Apk{
zipreader: zipreader,
}
if err = apk.parseResources(); err != nil {
return nil, err
}
if err = apk.parseManifest(); err != nil {
return nil, errorf("parse-manifest: %w", err)
}
return apk, nil
}
// Close is avaliable only if apk is created with OpenFile
func (k *Apk) Close() error {
if k.f == nil {
return nil
}
return k.f.Close()
}
// Icon returns the icon image of the APK.
func (k *Apk) Icon(resConfig *android_binary.ResTableConfig) (image.Image, error) {
iconPath, err := k.manifest.App.Icon.WithResTableConfig(resConfig).String()
if err != nil {
return nil, err
}
if android_binary.IsResID(iconPath) {
return nil, newError("unable to convert icon-id to icon path")
}
imgData, err := k.readZipFile(iconPath)
if err != nil {
return nil, err
}
m, _, err := image.Decode(bytes.NewReader(imgData))
return m, err
}
// Label returns the label of the APK.
func (k *Apk) Label(resConfig *android_binary.ResTableConfig) (s string, err error) {
s, err = k.manifest.App.Label.WithResTableConfig(resConfig).String()
if err != nil {
return
}
if android_binary.IsResID(s) {
err = newError("unable to convert label-id to string")
}
return
}
// Manifest returns the manifest of the APK.
func (k *Apk) Manifest() Manifest {
return k.manifest
}
// PackageName returns the package name of the APK.
func (k *Apk) PackageName() string {
return k.manifest.Package.MustString()
}
func isMainIntentFilter(intent ActivityIntentFilter) bool {
ok := false
for _, action := range intent.Actions {
s, err := action.Name.String()
if err == nil && s == "android.intent.action.MAIN" {
ok = true
break
}
}
if !ok {
return false
}
ok = false
for _, category := range intent.Categories {
s, err := category.Name.String()
if err == nil && s == "android.intent.category.LAUNCHER" {
ok = true
break
}
}
return ok
}
// MainActivity returns the name of the main activity.
func (k *Apk) MainActivity() (activity string, err error) {
for _, act := range k.manifest.App.Activities {
for _, intent := range act.IntentFilters {
if isMainIntentFilter(intent) {
return act.Name.String()
}
}
}
for _, act := range k.manifest.App.ActivityAliases {
for _, intent := range act.IntentFilters {
if isMainIntentFilter(intent) {
return act.TargetActivity.String()
}
}
}
return "", newError("No main activity found")
}
func (k *Apk) parseManifest() error {
xmlData, err := k.readZipFile("AndroidManifest.xml")
if err != nil {
return errorf("failed to read AndroidManifest.xml: %w", err)
}
xmlfile, err := android_binary.NewXMLFile(bytes.NewReader(xmlData))
if err != nil {
return errorf("failed to parse AndroidManifest.xml: %w", err)
}
return xmlfile.Decode(&k.manifest, k.table, nil)
}
func (k *Apk) parseResources() (err error) {
resData, err := k.readZipFile("resources.arsc")
if err != nil {
return
}
k.table, err = android_binary.NewTableFile(bytes.NewReader(resData))
return
}
func (k *Apk) readZipFile(name string) (data []byte, err error) {
buf := bytes.NewBuffer(nil)
for _, file := range k.zipreader.File {
if file.Name != name {
continue
}
rc, er := file.Open()
if er != nil {
err = er
return
}
defer rc.Close()
_, err = io.Copy(buf, rc)
if err != nil {
return
}
return buf.Bytes(), nil
}
return nil, fmt.Errorf("File %s not found", strconv.Quote(name))
}

View File

@@ -0,0 +1,108 @@
package apk
import "git.bvbej.com/bvbej/base-golang/pkg/android_binary"
// Instrumentation is an application instrumentation code.
type Instrumentation struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Target android_binary.String `xml:"http://schemas.android.com/apk/res/android targetPackage,attr"`
HandleProfiling android_binary.Bool `xml:"http://schemas.android.com/apk/res/android handleProfiling,attr"`
FunctionalTest android_binary.Bool `xml:"http://schemas.android.com/apk/res/android functionalTest,attr"`
}
// ActivityAction is an action of an activity.
type ActivityAction struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}
// ActivityCategory is a category of an activity.
type ActivityCategory struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
}
// ActivityIntentFilter is an androidbinary.Int32ent filter of an activity.
type ActivityIntentFilter struct {
Actions []ActivityAction `xml:"action"`
Categories []ActivityCategory `xml:"category"`
}
// AppActivity is an activity in an application.
type AppActivity struct {
Theme android_binary.String `xml:"http://schemas.android.com/apk/res/android theme,attr"`
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Label android_binary.String `xml:"http://schemas.android.com/apk/res/android label,attr"`
ScreenOrientation android_binary.String `xml:"http://schemas.android.com/apk/res/android screenOrientation,attr"`
IntentFilters []ActivityIntentFilter `xml:"intent-filter"`
}
// AppActivityAlias https://developer.android.com/guide/topics/manifest/activity-alias-element
type AppActivityAlias struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Label android_binary.String `xml:"http://schemas.android.com/apk/res/android label,attr"`
TargetActivity android_binary.String `xml:"http://schemas.android.com/apk/res/android targetActivity,attr"`
IntentFilters []ActivityIntentFilter `xml:"intent-filter"`
}
// MetaData is a metadata in an application.
type MetaData struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Value android_binary.String `xml:"http://schemas.android.com/apk/res/android value,attr"`
}
// Application is an application in an APK.
type Application struct {
AllowTaskReparenting android_binary.Bool `xml:"http://schemas.android.com/apk/res/android allowTaskReparenting,attr"`
AllowBackup android_binary.Bool `xml:"http://schemas.android.com/apk/res/android allowBackup,attr"`
BackupAgent android_binary.String `xml:"http://schemas.android.com/apk/res/android backupAgent,attr"`
Debuggable android_binary.Bool `xml:"http://schemas.android.com/apk/res/android debuggable,attr"`
Description android_binary.String `xml:"http://schemas.android.com/apk/res/android description,attr"`
Enabled android_binary.Bool `xml:"http://schemas.android.com/apk/res/android enabled,attr"`
HasCode android_binary.Bool `xml:"http://schemas.android.com/apk/res/android hasCode,attr"`
HardwareAccelerated android_binary.Bool `xml:"http://schemas.android.com/apk/res/android hardwareAccelerated,attr"`
Icon android_binary.String `xml:"http://schemas.android.com/apk/res/android icon,attr"`
KillAfterRestore android_binary.Bool `xml:"http://schemas.android.com/apk/res/android killAfterRestore,attr"`
LargeHeap android_binary.Bool `xml:"http://schemas.android.com/apk/res/android largeHeap,attr"`
Label android_binary.String `xml:"http://schemas.android.com/apk/res/android label,attr"`
Logo android_binary.String `xml:"http://schemas.android.com/apk/res/android logo,attr"`
ManageSpaceActivity android_binary.String `xml:"http://schemas.android.com/apk/res/android manageSpaceActivity,attr"`
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Permission android_binary.String `xml:"http://schemas.android.com/apk/res/android permission,attr"`
Persistent android_binary.Bool `xml:"http://schemas.android.com/apk/res/android persistent,attr"`
Process android_binary.String `xml:"http://schemas.android.com/apk/res/android process,attr"`
RestoreAnyVersion android_binary.Bool `xml:"http://schemas.android.com/apk/res/android restoreAnyVersion,attr"`
RequiredAccountType android_binary.String `xml:"http://schemas.android.com/apk/res/android requiredAccountType,attr"`
RestrictedAccountType android_binary.String `xml:"http://schemas.android.com/apk/res/android restrictedAccountType,attr"`
SupportsRtl android_binary.Bool `xml:"http://schemas.android.com/apk/res/android supportsRtl,attr"`
TaskAffinity android_binary.String `xml:"http://schemas.android.com/apk/res/android taskAffinity,attr"`
TestOnly android_binary.Bool `xml:"http://schemas.android.com/apk/res/android testOnly,attr"`
Theme android_binary.String `xml:"http://schemas.android.com/apk/res/android theme,attr"`
UIOptions android_binary.String `xml:"http://schemas.android.com/apk/res/android uiOptions,attr"`
VMSafeMode android_binary.Bool `xml:"http://schemas.android.com/apk/res/android vmSafeMode,attr"`
Activities []AppActivity `xml:"activity"`
ActivityAliases []AppActivityAlias `xml:"activity-alias"`
MetaData []MetaData `xml:"meta-data"`
}
// UsesSDK is target SDK version.
type UsesSDK struct {
Min android_binary.Int32 `xml:"http://schemas.android.com/apk/res/android minSdkVersion,attr"`
Target android_binary.Int32 `xml:"http://schemas.android.com/apk/res/android targetSdkVersion,attr"`
Max android_binary.Int32 `xml:"http://schemas.android.com/apk/res/android maxSdkVersion,attr"`
}
// UsesPermission is user grant the system permission.
type UsesPermission struct {
Name android_binary.String `xml:"http://schemas.android.com/apk/res/android name,attr"`
Max android_binary.Int32 `xml:"http://schemas.android.com/apk/res/android maxSdkVersion,attr"`
}
// Manifest is a manifest of an APK.
type Manifest struct {
Package android_binary.String `xml:"package,attr"`
VersionCode android_binary.Int32 `xml:"http://schemas.android.com/apk/res/android versionCode,attr"`
VersionName android_binary.String `xml:"http://schemas.android.com/apk/res/android versionName,attr"`
App Application `xml:"application"`
Instrument Instrumentation `xml:"instrumentation"`
SDK UsesSDK `xml:"uses-sdk"`
UsesPermissions []UsesPermission `xml:"uses-permission"`
}

View File

@@ -0,0 +1,9 @@
package apk
import (
"errors"
"fmt"
)
var newError = errors.New
var errorf = fmt.Errorf