Android 침묵 설치 와 스마트 설치 의 실현 방법
최근 안 드 로 이 드 의 침묵 설치 와 스마트 설 치 를 연구 해 블 로그 에 기록 했다.침묵 설치 란 소리 없 이 배경 에 apk 를 설치 하 는 것 으로 인터페이스 알림 이 없습니다.스마트 설 치 는 설치 인터페이스 가 있 지만 모두 자동 이 므 로 사용자 가 클릭 할 필요 가 없다.
우선 두 가 지 를 강조 합 니 다:침묵 설 치 는 루트 권한 이 있어 야 합 니 다.스마트 설 치 는 사용자 가 수 동 으로 무장 애 서 비 스 를 시작 해 야 합 니 다.
2 원리
침묵 설치,마 운 트 해제 의 원 리 는 pm install 명령 을 이용 하여 apk 를 설치 하 는 것 입 니 다.pm uninstall 은 apk 를 마 운 트 해제 하 는 것 입 니 다.스마트 설 치 는 안 드 로 이 드 시스템 이 제공 하 는 무장 애 서비스 Accessibility Service 를 이용 하여 사용자 의 클릭 을 모 의 하여 자동 으로 설치 하 는 것 입 니 다.
3pm 명령 안내
(1) pm install
pm install 명령 의 용법 및 매개 변 수 는 다음 과 같 습 니 다.
<code class="hljs haml">pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH
Options:
-l: install the package with FORWARD_LOCK.
-r: reinstall an exisiting app, keeping its data.
-t: allow test .apks to be installed.
-i: specify the installer package name.
-s: install package on sdcard.
-f: install package on internal flash.</code>
(2) pm uninstallpm uninstall 명령 의 용법 및 매개 변 수 는 다음 과 같 습 니 다.
<code class="hljs livecodeserver">pm uninstall [-k] PACKAGE
Options:
-k: keep the data and cache directories around.</code>
위의 영 어 는 매우 간단 해서 설명 하지 않 는 다.4 침묵 설치
프 리 젠 테 이 션 을 편리 하 게 하기 위해 서,나 는 아이 치 이의 설치 패 키 지 를 test.apk 라 고 이름 을 바 꾸 어 sdcard 에 놓 았 다.당신 은 스스로 아이 치 이 홈 페이지 에 가서 다운로드 할 수도 있 고,스스로 apk 를 찾 아 sdcard 에 올 릴 수도 있 습 니 다.그러나 apk 의 가방 이름 을 알 아야 합 니 다.나중에 마 운 트 해제 할 때 사용 해 야 합 니 다.
선행 코드:
<code class="hljs cs">//
private void installSlient() {
String cmd = "pm install -r /mnt/sdcard/test.apk";
Process process = null;
DataOutputStream os = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
try {
// root
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.write(cmd.getBytes());
os.writeBytes("
");
os.writeBytes("exit
");
os.flush();
//
process.waitFor();
//
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//
tvTest.setText(" :" + successMsg.toString() + "
" + " : " + errorMsg.toString());
}</code>
이 코드 는 프로그램 에서 pm 명령 을 실행 하 는 것 입 니 다.adb 에서 실행pm install -r /mnt/sdcard/test.apk
하 는 것 과 효과 가 같 습 니 다.관건 적 인 코드 는Runtime.getRuntime().exec(“su”)
입 니 다.이 코드 는 루트 권한 을 요구 하기 때문에 핸드폰 은 루트 가 필요 합 니 다.루트 가 싫 으 면 시 뮬 레이 터 를 사용 하 셔 도 됩 니 다. Runtime.getRuntime().exec(“su”)
를 통 해 프로 세 스 대상 을 가 져 오 면 명령 을 쓸 수 있 습 니 다.명령 을 쓸 때마다 줄 을 바 꾸 고''를 쓰 면 됩 니 다.마지막 으로 exit 를 쓰 고 명령 이 실 행 된 환경 을 떠 납 니 다.5.조용히 마 운 트 해제
침묵 마 운 트 해제 와 침묵 설치 가 같 습 니 다.명령 만 다 릅 니 다.침묵 마 운 트 해제 에는 가방 이름 이 필요 합 니 다.마찬가지 로 침묵 마 운 트 해제 에 도 루트 권한 이 필요 합 니 다.
코드 보기:
<code class="hljs java">// apk
private static final String PACKAGE_NAME = "com.qiyi.video";
//
private void uninstallSlient() {
String cmd = "pm uninstall " + PACKAGE_NAME;
Process process = null;
DataOutputStream os = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
try {
// root
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.write(cmd.getBytes());
os.writeBytes("
");
os.writeBytes("exit
");
os.flush();
//
process.waitFor();
//
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//
tvTest.setText(" :" + successMsg.toString() + "
" + " : " + errorMsg.toString());
}</code>
침묵 설치 와 같은 코드 는 설명 하지 않 습 니 다.그리고 만약 에 apk 의 가방 이름 을 모른다 면 컴 파일 한 후에 AndroidManifest.xml 파일 을 보 세 요.만약 에 이 파일 을 열 면 모두 어 지 러 운 코드 입 니 다.헷 갈 렸 다 는 것 을 설명 합 니 다.그러면 직접 설치 한 다음 에/data/data 아래 에 가서 가방 을 찾 으 세 요.물론 핸드폰 은 root 가 있어 야/data/data 디 렉 터 리 에 들 어 갈 수 있 습 니 다.6 스마트 설치
스마트 설 치 는 조금 번 거 롭 습 니 다.원 리 는 안 드 로 이 드 가 제공 하 는 Accessibility Service 서 비 스 를 사용 하 는 것 입 니 다.이 서 비 스 는 화면의 노드 를 얻 을 수 있 습 니 다.한 노드 는 하나의 view 입 니 다.우리 가 쓴 xml 파일 에 있 는 모든 라벨 은 하나의 노드 입 니 다.그 다음 에 사용자 의 조작 을 모 의 한 다음 에 이 노드 에 대해 클릭,미끄럼 등 작업 을 할 수 있 습 니 다.저 희 는 이 원 리 를 이용 하여 설치 단 추 를 자동 으로 클릭 합 니 다.물론 이 서 비 스 를 사용 하려 면 사용자 가 수 동 으로 무장 애 서 비 스 를 켜 야 합 니 다.구체 적 인 실현 방법 을 살 펴 보 자.
(1)AccessibilityService 프로필 만 들 기
res 디 렉 터 리 에 xml 디 렉 터 리 를 만 든 다음 xml 디 렉 터 리 에 accessibility 를 만 듭 니 다.service_config.xml 파일,내용 은 다음 과 같 습 니 다.
res/xml/accessibility_service_config.xml:
<code class="hljs xml" data-filtered="filtered"></accessibility-service></code>
access bility EventTypes:감청 창 에서 어떤 사건 을 모 의 할 수 있 는 지 지정 합 니 다.type:AllMask 는 모든 사건 을 모 의 할 수 있 음 을 표시 합 니 다.accessibility Feedback Type:무장 애 서비스의 피드백 방식 을 지정 합 니 다.
canRetrieveWindow Content:프로그램 이 창의 노드 와 내용 을 읽 을 수 있 는 지 여 부 를 지정 합 니 다.물론 true 입 니 다.
description:사용자 가 수 동 으로 서 비 스 를 설정 할 때 사용자 에 게 보 여 줍 니 다.
packageNames:어떤 프로그램의 창 활동 을 감청 할 지 지정 합 니 다.com.android.packageinstaller 는 Android 시스템 의 설치 인 터 페 이 스 를 감청 합 니 다.
나머지 매개 변 수 는 그대로 쓰 면 된다.
res/strings.xml:
<code class="hljs xml"><resources>
<string name="app_name">SlientInstallTest</string>
<string name="desc"> app </string>
</resources></code>
(2)AccessibilityService 서비스 만 들 기
<code class="hljs java">public class MyAccessibilityService extends AccessibilityService {
private static final String TAG = "[TAG]";
private Map<integer, boolean=""> handleMap = new HashMap<>();
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo nodeInfo = event.getSource();
if (nodeInfo != null) {
int eventType = event.getEventType();
if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (handleMap.get(event.getWindowId()) == null) {
boolean handled = iterateNodesAndHandle(nodeInfo);
if (handled) {
handleMap.put(event.getWindowId(), true);
}
}
}
}
}
@Override
public void onInterrupt() {
}
// ,
private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo != null) {
int childCount = nodeInfo.getChildCount();
if ("android.widget.Button".equals(nodeInfo.getClassName())) {
String nodeCotent = nodeInfo.getText().toString();
Log.d(TAG, "content is: " + nodeCotent);
if (" ".equals(nodeCotent) || " ".equals(nodeCotent) || " ".equals(nodeCotent)) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
// ScrollView
else if ("android.widget.ScrollView".equals(nodeInfo.getClassName())) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
for (int i = 0; i < childCount; i++) {
AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
if (iterateNodesAndHandle(childNodeInfo)) {
return true;
}
}
}
return false;
}
}</integer,></code>
apk 설치 인터페이스 에 들 어가 면 onAccessibilityEvent()방법 을 되 돌려 줍 니 다.저 희 는 TYPE 에 만 관심 이 있 습 니 다.WINDOW_CONTENT_CHANGED 와 TYPEWINDOW_STATE_CHANGED 두 이 벤트 는 중복 처 리 를 방지 하기 위해 하나의 map 로 이 벤트 를 걸 러 내 고 그 다음 에 노드 를 옮 겨 다 니 며'설치','완료','확인'단 추 를 찾 으 면 클릭 합 니 다.설치 인터페이스 가 굴 러 야 설치 단추 가 나타 나 기 때문에 ScrollView 를 만 났 을 때 스크롤 합 니 다.(3)AndroidManifest 에 서비스 설정
<code class="hljs xml"><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER">
</category></action></intent-filter>
</activity>
<service android:label=" App" android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
</action></intent-filter>
<meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config">
</meta-data></service>
</application></uses-permission></code>
포 인 트 는 뒤의 service 태그 입 니 다.android:label:이것 이 바로 사용자 가 본 무장 애 서비스의 이름 입 니 다.
android:permission:BIND 를 사용 해 야 합 니 다.ACCESSIBILITY_서비스 라 는 권한.
action:android.accessibility service.accessibility Service 는 이 action 이 있어 야 사용자 가 설정 에서 우리 의 서 비 스 를 볼 수 있 습 니 다.그렇지 않 으 면 사용자 가 우리 가 쓴 서 비 스 를 시작 할 수 없고 우리 가 쓴 MyAccessibility Service 에 들 어 갈 수 없습니다.따라서 잘못 쓰 지 않도록 주의 하 십시오.무장 애 서비스 에 우리 가 쓴 서비스 가 없 는 것 을 발견 하면 여 기 를 확인 하 십시오.
(4)스마트 설치 코드 호출
앞 에 준비 작업 이 끝 난 후에 지금 사용 해 야 합 니 다.스마트 설치 코드 는 다음 과 같 습 니 다.
<code class="hljs cs"> //
private void smartInstall() {
Uri uri = Uri.fromFile(new File("/mnt/sdcard/test.apk"));
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(localIntent);
}</code>
(5)스마트 설치 서비스 수 동 설정코드 가 실 행 된 후에 사용자 가 스마트 설치 서 비 스 를 켜 서 사용자 가 스스로 찾 도록 하 는 것 은 현명 하지 못 하기 때문에 우 리 는 자발적으로 설정 인터페이스 로 뛰 어야 한다.코드 는 다음 과 같다.
<code class="hljs cs">//
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);</code>
다음 그림 과 같이 설정:보이 시 나 요?위 에 표 시 된 것 은 Service 에 있 는 label 의 값 입 니 다.위 에 옵션 이 없 으 면 AndroidManifest 에 있 는 Service 설정 을 확인 하 십시오.
'스마트 설치 앱'을 클릭 하여 서 비 스 를 시작 합 니 다.다음 그림:
그 중의 제시 문 자 는 바로 우리 가 res/xml/accessibilityservice_config.xml 파일 에 설 정 된 description 속성
7.우리 만 쓰 는 app 은 자동 으로 설치 할 수 있 습 니 다.
이렇게 코드 를 쓰 면 실행 할 수 있 습 니 다.단 추 를 누 르 면 sdcard 에 있 는 test.apk 를 자동 으로 설치 합 니 다.그러나 모든 apk 가 자동 으로 설치 되 는 것 을 발견 할 수 있 습 니 다.이것 은 우리 의 요구 에 부합 되 지 않 습 니 다.우 리 는 우리 가 쓴 app 을 통 해 자동 으로 설치 할 수 있 고 다른 apk 는 사용자 가 수 동 으로 주문 해 야 합 니 다.이 문 제 를 어떻게 해결 합 니까?
사고방식:MainActivity 에서 Public static boolean flag 를 만 들 고 MyAccessibility Service 의 onAccessibility Event()에 flag 판단 을 추가 한 다음 에 스마트 설치 전 flag 를 true 로 호출 하여 apk 설치 이벤트 의 방송 수신 기 를 만 듭 니 다.apk 설치 가 완 료 된 후에 false 를 false 로 설정 하면 다른 apk 가 자동 으로 설치 되 지 않 고 이 문 제 를 해결 할 수 있 습 니 다.
아래 위의 전체 코드.
8 전체 코드
app/MainActivity.java:
<code class="hljs java">public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "[TAG][MainActivity]";
private static final String PACKAGE_NAME = "com.qiyi.video";
private String apkPath = "/mnt/sdcard/test.apk";
public static boolean flag = false;// app
private TextView tvTest;
private MyInstallReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTest = (TextView) findViewById(R.id.tv_test);
findViewById(R.id.btn_install).setOnClickListener(this);
findViewById(R.id.btn_uninstall).setOnClickListener(this);
findViewById(R.id.btn_set).setOnClickListener(this);
findViewById(R.id.btn_smart_install).setOnClickListener(this);
// apk
receiver = new MyInstallReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.PACKAGE_ADDED");
filter.addAction("android.intent.action.PACKAGE_REMOVED");
filter.addDataScheme("package");
this.registerReceiver(receiver, filter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//
case R.id.btn_install:
installSlient();
break;
//
case R.id.btn_uninstall:
uninstallSlient();
break;
//
case R.id.btn_set:
//
Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
startActivity(intent);
break;
//
case R.id.btn_smart_install:
// app
flag = true;
smartInstall();
break;
}
}
//
private void installSlient() {
String cmd = "pm install -r /mnt/sdcard/test.apk";
Process process = null;
DataOutputStream os = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
try {
// root
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.write(cmd.getBytes());
os.writeBytes("
");
os.writeBytes("exit
");
os.flush();
//
process.waitFor();
//
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//
tvTest.setText(" :" + successMsg.toString() + "
" + " : " + errorMsg.toString());
}
//
private void uninstallSlient() {
String cmd = "pm uninstall " + PACKAGE_NAME;
Process process = null;
DataOutputStream os = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
try {
// root
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.write(cmd.getBytes());
os.writeBytes("
");
os.writeBytes("exit
");
os.flush();
//
process.waitFor();
//
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (process != null) {
process.destroy();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
//
tvTest.setText(" :" + successMsg.toString() + "
" + " : " + errorMsg.toString());
}
//
private void smartInstall() {
Uri uri = Uri.fromFile(new File(apkPath));
Intent localIntent = new Intent(Intent.ACTION_VIEW);
localIntent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(localIntent);
}
// apk
private class MyInstallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) { // install
String packageName = intent.getDataString();
Log.i(TAG, " :" + packageName);
// , flag, apk
flag = false;
}
if (intent.getAction().equals("android.intent.action.PACKAGE_REMOVED")) { // uninstall
String packageName = intent.getDataString();
Log.i(TAG, " :" + packageName);
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (receiver != null) {
unregisterReceiver(receiver);
}
}
}</code>
화면 에 세 개의 버튼 만 있다.res/layout/activity_main.xml:
<code class="hljs xml"><!--?xml version="1.0" encoding="utf-8"?-->
<relativelayout android:layout_height="match_parent" android:layout_width="match_parent" android:paddingbottom="@dimen/activity_vertical_margin" android:paddingleft="@dimen/activity_horizontal_margin" android:paddingright="@dimen/activity_horizontal_margin" android:paddingtop="@dimen/activity_vertical_margin" xmlns:android="https://schemas.android.com/apk/res/android" xmlns:tools="https://schemas.android.com/tools">
<textview android:id="@+id/tv_test" android:layout_height="wrap_content" android:layout_width="match_parent" android:text=""><button android:id="@+id/btn_install" android:layout_centerinparent="true" android:layout_height="wrap_content" android:layout_width="match_parent" android:text=" "></button><button android:id="@+id/btn_uninstall" android:layout_below="@id/btn_install" android:layout_height="wrap_content" android:layout_width="match_parent" android:text=" "></button><button android:id="@+id/btn_set" android:layout_below="@id/btn_uninstall" android:layout_height="wrap_content" android:layout_width="match_parent" android:text=" "></button></textview></relativelayout></code><button android:id="@+id/btn_smart_install" android:layout_below="@id/btn_set" android:layout_height="wrap_content" android:layout_width="match_parent" android:text=" "><code class="hljs xml">
</code></button>
서비스 프로필res/xml/accessibility_service_config.xml
<code class="hljs xml" data-filtered="filtered"></accessibility-service></code>
지능 설치 서비스app/MyAccessibilityService.java:
<code class="hljs java">public class MyAccessibilityService extends AccessibilityService {
private static final String TAG = "[TAG]";
private Map<integer, boolean=""> handleMap = new HashMap<>();
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo nodeInfo = event.getSource();
if (nodeInfo != null && MainActivity.flag) {
int eventType = event.getEventType();
if (eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED || eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
if (handleMap.get(event.getWindowId()) == null) {
boolean handled = iterateNodesAndHandle(nodeInfo);
if (handled) {
handleMap.put(event.getWindowId(), true);
}
}
}
}
}
@Override
public void onInterrupt() {
}
// ,
private boolean iterateNodesAndHandle(AccessibilityNodeInfo nodeInfo) {
if (nodeInfo != null) {
int childCount = nodeInfo.getChildCount();
if ("android.widget.Button".equals(nodeInfo.getClassName())) {
String nodeCotent = nodeInfo.getText().toString();
Log.d(TAG, "content is: " + nodeCotent);
if (" ".equals(nodeCotent) || " ".equals(nodeCotent) || " ".equals(nodeCotent)) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
return true;
}
}
// ScrollView
else if ("android.widget.ScrollView".equals(nodeInfo.getClassName())) {
nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
}
for (int i = 0; i < childCount; i++) {
AccessibilityNodeInfo childNodeInfo = nodeInfo.getChild(i);
if (iterateNodesAndHandle(childNodeInfo)) {
return true;
}
}
}
return false;
}
}</integer,></code>
마지막 으로 프로필 AndroidManifest.xml:
<code class="hljs xml"><manifest package="com.slientinstalltest" xmlns:android="https://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER">
</category></action></intent-filter>
</activity>
<service android:label=" App" android:name=".MyAccessibilityService" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
<intent-filter>
</action></intent-filter>
<meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibility_service_config">
</meta-data></service>
</application>
</uses-permission></manifest></code>
메모:설치 할 apk 를 sdcard 에 올 리 고 코드 에 있 는 apk 경로 와 가방 이름 을 수정 하 십시오.9 실행 효과
10 총화
Android 스마트 설치 의 원 리 는 갈고리 와 유사 한 서 비 스 를 이용 한 것 입 니 다.이 서 비 스 는 위 챗 에서 보 너 스 를 빼 앗 는 개발 에 도 사용 할 수 있 습 니 다.어 떻 습 니까?ios 보다 재 미 있 는 것 이 아 닙 니까?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.