본문 바로가기
  • 일하면서 배운 내용 끄적이는 블로그
안드로이드

안드로이드 앱 내에서 apk 파일 설치하기

by dhl7799 2024. 11. 28.

현재 작업중인 앱이 로그인 시 VPN이 연결되어야 하는데

고객사에서 사용하는 VPN이 라이브러리를 추가 하고 apk 파일도 별도로 설치해야함..

 

근데 애초에 VPN이 연결이 안되면 사이트 접속이 안되니 설치페이지같은것도 못쓰고

apk 파일 자체를 프로젝트 안에다가 넣어놓고

앱 실행 시 설치여부 확인해서 없으면 설치하는 식으로 작업했다.

 

 

먼저 apk 파일 위치는 src/main/res/raw

파일 확장자는 처음에 .apk로 붙였는데 그러면 나중에 R.raw.대충파일명.apk로 인식이 안돼서 _apk로 수정

 

대충 나머진 설치가 순차적으로 여러개 진행돼서 필요한거고 apk 설치는 

vpnManager.installApk(R.raw.****vpn_apk, Common.VPN_FILE_NAME, new CompleteCallback() {
	@Override
	public void onSuccess() {
		vpnCallback.accept(true, null);
	}

	@Override
	public void onError(Throwable error) {
		vpnCallback.accept(false, error);
    }
});

 

이부분

src/main/res/raw 아래 넣은 실제 파일 명을 R.raw.****vpn_apk로 넣고, Common.VPN_FILE_NAME은 원래 파일명

( src/main/res/raw 경로에 파일 넣을때 대문자도, 특수기호도 안돼서 바꿔야했음..)

 

CompleteCallback은 콜백처리 하려고 넣은거

public interface CompleteCallback {
    void onSuccess();
    void onError(Throwable throwable);
}

 

이렇게생김

 

다음은 installApk 함수

public void installApk(int rawResId, String fileName, CompleteCallback callback) {
	if (bindVpnService()) {
		callback.onSuccess();
		return;
	}

	try {
		// res/raw에서 APK 파일을 파일 시스템으로 복사
		File apkFile = new File(context.getFilesDir(), fileName);
		if (!apkFile.exists()) {
			try (InputStream in = context.getResources().openRawResource(rawResId);
				FileOutputStream out = new FileOutputStream(apkFile)) {
				byte[] buffer = new byte[4096];
				int bytesRead;
				while ((bytesRead = in.read(buffer)) != -1) {
					out.write(buffer, 0, bytesRead);
				}
			}
        }

		File file = new File(context.getFilesDir(), fileName);
		Uri apkUri = FileProvider.getUriForFile(context, "com.(대충패키지명).fileprovider", file);

		Intent intent = new Intent(Intent.ACTION_VIEW);
		intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
		intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
		context.startActivity(intent);

		// 성공 콜백 호출
		callback.onSuccess();
	} catch (IOException e) {
		callback.onError(e);
	}
}

 

res 폴더는 읽기전용이라 실행하려면 파일 시스템 내부로 복사해야한다고 함

 

그런 다음 실행시킴

 

설정은 

 

패키지 설치 권한 추가하고

 

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

 

src/main/res 아래에 xml 폴더 추가해서 file_paths.xml 파일 생성

내용은 아래와 같음

<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- 외부 파일 디렉토리 예시 -->
<external-path name="external_files" path="." />
<!-- 파일을 저장할 내부 디렉토리 -->
<files-path name="internal_files" path="." />
</paths>

 

그러고 AndroidManifext.xml에 application 안에

<!-- FileProvider 설정 -->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.nanum.android.NanumGroupWareKDHC.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>

 

FileProvider 추가

 

이러면 installApk가 실행됐을때 설치가 시작된다.

 

마지막으로 설치가 됐는지 확인은 broadcast 사용하는 방법도 있다는데

일단 로그인 시도 시 apk파일로 설치한 vpn 앱의 패키지명을 이용해서 설치여부를 확인하는 방향으로 감

public boolean isVpnInstalled() {
	PackageManager packageManager = context.getPackageManager();
	try {
		packageManager.getPackageInfo(Common.VPN_PACKAGE_NAME, PackageManager.GET_ACTIVITIES);
		return true; // 패키지가 설치되어 있음
	} catch (PackageManager.NameNotFoundException e) {
		return false; // 패키지가 설치되지 않음
	}
}