#2023盲盒+码# 设备端直装hap的具体方案
  noedAHRF1iby 2023年11月02日 523 0

【本文正在参加 2023「盲盒」+码有奖征文活动】 https://ost.51cto.com/posts/25284

序言

之前在《OpenHarmony设备直装hap脱离电脑hdc的两种实现思路》一文中,我提到了两种实现直装hap的思路,那本篇文章我将详细讲解下第一种思路的具体实现方式,至于第二种另辟蹊径的实现思路,我会在后续的文章中继续分享实现原理。

第一种思路是用到了官方的包管理模块的API,由于包管理的installer模块接口的权限,需要 ohos.permission.INSTALL_BUNDLE system_core 级别的系统权限,所以我们需要配置项目权限和访问控制权限

项目权限配置

entry/src/main/module.json5

{
  "name": "ohos.permission.INSTALL_BUNDLE",
},

访问控制权限配置

openharmony-sdk\9\toolchains\lib\UnsgnedReleasedProfileTemplate.json

"apl":"system_core",
"app-feature":"hos_system_app"

安装应用

  • hap包要放到设备真实路径:/data/app/el2/用户ID/base/应用包名/haps/entry/files/
  • hapFilePaths写沙箱路径:/data/storage/el2/base/haps/entry/files/
import installer from '@ohos.bundle.installer';
import promptAction from '@ohos.promptAction';

function installApp() {
  let hapFilePaths = ['/data/storage/el2/base/haps/entry/files/testapp.hap'];
  let installParam = {
    userId: 100,
    isKeepData: false,
    installFlag: 1,
  };

  try {
    installer.getBundleInstaller().then(data => {
      data.install(hapFilePaths, installParam, err => {
        if (err) {
          console.error('install failed:' + err.message);
          promptAction.showToast({message: '安装失败:' + err.message, duration: ToastDuration});
        } else {
          console.info('install successfully.');
          promptAction.showToast({message: '安装成功', duration: ToastDuration});
        }
      });
    }).catch(error => {
      console.error('getBundleInstaller failed. Cause: ' + error.message);
      promptAction.showToast({message: '安装失败:' + error.message, duration: ToastDuration});
    });
  } catch (error) {
    console.error('getBundleInstaller failed. Cause: ' + error.message);
    promptAction.showToast({message: '安装失败:' + error.message, duration: ToastDuration});
  }
}

打开应用

指定包名和abilityName,调用context.startAbility打开目标应用

import common from '@ohos.app.ability.common';
import promptAction from '@ohos.promptAction';

function openApp() {
  let context = getContext(this) as common.UIAbilityContext;
  context.startAbility({
    bundleName: 'com.example.testapp',
    abilityName: 'EntryAbility',
    moduleName: ''
  }).then(() => {
    console.error('startApplication promise success');
    promptAction.showToast({message: '打开成功', duration: ToastDuration});
  }, (err) => {
    console.error(`startApplication promise error: ${JSON.stringify(err)}`);
    promptAction.showToast({message: '打开失败:应用不存在', duration: ToastDuration});
  });
}

卸载应用

指定包名和参数卸载应用

import installer from '@ohos.bundle.installer';
import promptAction from '@ohos.promptAction';

function uninstallApp() {
  let bundleName = 'com.example.testapp';
  let installParam = {
    userId: 100,
    isKeepData: false,
    installFlag: 1
  };

  try {
    installer.getBundleInstaller().then(data => {
      data.uninstall(bundleName, installParam, err => {
        if (err) {
          console.error('uninstall failed:' + err.message);
          promptAction.showToast({message: '卸载失败:应用不存在', duration: ToastDuration});
        } else {
          console.info('uninstall successfully.');
          promptAction.showToast({message: '卸载成功', duration: ToastDuration});
        }
      });
    }).catch(error => {
      console.error('getBundleInstaller failed. Cause: ' + error.message);
      promptAction.showToast({message: '卸载失败:' + error.message, duration: ToastDuration});
    });
  } catch (error) {
    console.error('getBundleInstaller failed. Cause: ' + error.message);
    promptAction.showToast({message: '卸载失败:' + error.message, duration: ToastDuration});
  }
}

第二种思路是:开发一个shell命令服务放到系统内,用于操作bm/aa等本地shell命令去安装和打开应用,并提供http或其他协议的接口给上层应用调用。很明显这种方式违背了OpenHarmony的访问控制权限机制,只需要申请一个基本的INTERNET权限用于调用本机接口即可,这种方式很不安全,只是探索研究和尝试。

开发shell服务

这里以go语言为例

myshell.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"strings"
)

func main() {
	http.HandleFunc("/execCommand", ExecCommand)
	err := http.ListenAndServe("0.0.0.0:23333", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func ExecCommand(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name")
	args := r.FormValue("args")

	argsArr := strings.Split(args, " ")
	cmd := exec.Command(name, argsArr...)

	out, err := cmd.CombinedOutput()
	if err != nil {
		_, err := fmt.Fprintf(w, err.Error())
		if err != nil {
			return
		}
		return
	}

	_, err = fmt.Fprintf(w, string(out))
	if err != nil {
		return
	}
}

在 windows 平台上交叉编译生成 linux arm64 平台的的可执行程序

SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=arm64
go build -o myshell myshell.go

配置shell服务开机自启

编写一个 myshell.cfg 文件,用于描述开机自启shell服务的信息

{
    "import" : [],
    "jobs" : [{
            "name" : "init",
            "cmds" : [
                "start myshell"
            ]
        }
    ],
    "services" : [{
            "name" : "myshell",
            "path" : ["/system/bin/myshell"]
        }
    ]
}

推送 myshellmyshell.cfg 到系统目录,然后重启设备,此服务将开机自启

hdc shell mount -o remount,rw /
hdc file send myshell /system/bin/myshell
hdc file send myshell.cfg /system/etc/init/myshell.cfg
hdc shell chmod 777 /system/bin/myshell
hdc shell reboot

项目权限配置

entry/src/main/module.json5

{
  "name": "ohos.permission.INTERNET",
},

安装应用

调用刚才开发的shell服务提供的htpp接口,传递两个参数,第一个name是调用本地shell的绝对路径,第二个args是要执行命令的参数

import http from '@ohos.net.http';

function installAppByMyShell() {
  let httpRequest = http.createHttp();
  httpRequest.request("http://127.0.0.1:23333/execCommand", {
    method: http.RequestMethod.POST,
    header: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    extraData: "name=/bin/bm&args=install -r -p /data/local/tmp/testapp.hap",
  }, (err, data) => {
    if (!err) {
      if (data.responseCode == 200) {
        if (data.result.toString().startsWith("install bundle successfully.")) {
          promptAction.showToast({message: '安装成功', duration: ToastDuration});
        } else {
          promptAction.showToast({message: '安装失败', duration: ToastDuration});
        }
      }
    } else {
      console.info('error:' + JSON.stringify(err));
      httpRequest.destroy();
    }
  }
  );
}

打开/卸载应用

由于这种实现方法的特殊性,你可以通过http接口调用任何本地的shell命令,因此,你可以调用bm/aa等本地shell去实现打开应用、卸载应用,甚至是其他的任何操作~

本文作者:westinyang

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com/#bkwz​

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
noedAHRF1iby