앱을 만들다 보니 다른 사람이 어떤 특정한 앱을 설치하고 있는지 확인해야 할 일이 생겼다.
그래서 일단은 남이 만들어 놓은 라이브러리를 사용하려 했는데 0.60 이상을 지원하지 않는 것 같아서 결국은 코드를 직접 만들어서 쓰게 되었다.
https://reactnative.dev/docs/native-modules-intro
iOS 의 경우에는 해당 앱이 제공하는 custom URL Scheme 이 있어서 이를 열 수 있는지 확인하는 로직을 이용하여 Native module 을 구현할 필요 없이 쉽게 구현하였다. (react-native 의 Linking 라이브러리 사용)
// Instagram 이 유저의 기기에 설치되어있는지 확인한다.
export const instagramCheckIOS = async () => {
try {
const res = await checkURLScheme('instagram', 'app');
return res;
} catch (error) {
console.warn('instagramCheckIOS FAILED', error);
return false;
}
};
const checkURLScheme = (proto, query) => {
return new Promise((resolve, reject) => {
Linking.canOpenURL(proto + '://' + query || '')
.then((isInstalled) => {
resolve(isInstalled);
})
.catch((err) => {
reject(err);
});
});
};
Android 의 경우 간단한 java class 를 하나 만들어서 Native Modules 를 이용하여 처리하였는데, 여기에 그 네이티브 모듈을 연결하는 것을 다 기술하는 것은 조금 번거로울 듯 싶어서 해당 코드를 짤 때 주의해야했던 것들만 적고 마친다. 네이티브 모듈을 만들고 이를 리액트 네이티브에 넣는 것은 해볼만한 가치가 있으니 피할 수 없으면 즐기도록 하자.
https://reactnative.dev/docs/native-modules-android
다음은 해당 패키지가 깔려있는지 확인하는 java 코드이다.
package 우리회사.패키지.네임;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import java.util.Map;
import java.util.HashMap;
import android.util.Log;
import android.content.pm.PackageManager;
import android.content.Context;
public class AppInstallCheckModule extends ReactContextBaseJavaModule {
Context ctx;
AppInstallCheckModule(ReactApplicationContext reactContext) {
super(reactContext);
this.ctx = reactContext.getApplicationContext();
}
@Override
public String getName() {
return "AppInstallCheckModule";
}
@ReactMethod
public void isPackageInstalled(String packageName, Callback cb) {
PackageManager pm = this.ctx.getPackageManager();
try {
pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
cb.invoke(true);
} catch (Exception e) {
cb.invoke(false);
}
}
}
Android 의 PackageManaer 모듈을 이용하면 간단하게 패키지 이름의 앱이 깔려있는지 확인할 수 있다. (예를들어 인스타그램의 패키지 이름인 'com.instagram.android' 같은 스트링을 input 으로 넣으면 확인 가능.)
테스트할 때는 정상 동작하는데 막상 실 기기에서는 자꾸 앱 설치가 안되어있다고 하여 당황하였는데 살펴보니 안드로이드 API 버젼 30 이후부터는 AndroidManifest 에 현재 찾고자 하는 패키지의 이름을 따로 명시하지 않으면 그 앱이 깔려있는지 알려주지 않는 보안 정책이 생긴 것 같다. 그래서 Android Manifest 에 필요한 부분을 더 추가해주었다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="우리회사.패키지.네임">
...
<queries>
<package android:name="com.kakao.talk" />
<package android:name="com.instagram.android" />
<package android:name="com.google.android.youtube" />
</queries>
...
참고)
https://developer.android.com/training/basics/intents/package-visibility