I'm working on auto update module in react native. For android version, app should download apk of the new version and installs it. It's possible to download the apk by using react-native-fs, but how can i install the apk? Or being more general, how can i run external files in the react native app?
-
Have you seen the code-push framework ? It's a tool to do auto updates on react-native apps. If your final goal is to do auto update, maybe this tool can help you. – Gui Herzog Jan 03 '17 at 08:09
-
yes, but i think it's just to update JS bundle. I want to install the new version of the app, so native codes updated too. – Meysam Izadmehr Jan 03 '17 at 10:02
3 Answers
Nope. You can't in generic case (may be this possible on rooted devices).
It is google market (or vendor market) task. It should work out of the box when you push new version of app to market, of course users can opt in auto update.
However you can launch install dialog, see: Install Application programmatically on Android
To download file the application can use react-native-fs module.
To open Intent with explicit data type application/vnd.android.package-archive
one can use react-native-mime-intent.

- 1
- 1
-
thanks for your answer. i just want to launch install dialog. can you explain more about opening intent by linking? – Meysam Izadmehr Jan 04 '17 at 14:09
-
I have never done this for apk types, but think it should be as simple as: Linking.openUrl('file://path-to-apk.apk').then(...).catch(...) – Jan 04 '17 at 15:24
-
I test `Linking.openUrl('file://path-to-apk.apk')` but it's not working. It's not open apk with installer, just want to open it. In android, it's possible to send _application/vnd.android.package-archive_ as argument to the intent, how can i do it in react native? – Meysam Izadmehr Jan 07 '17 at 05:42
-
Ok, so you need write some native code, or use already existent third-party package. Fast search suggest something like: https://github.com/veeloinc/react-native-mime-intent – Jan 07 '17 at 05:49
-
thanks, now i can use _application/vnd.android.package-archive_. Right now i'm getting error : _There was a problem parsing package_, do you have any idea? – Meysam Izadmehr Jan 07 '17 at 08:08
-
No, see adb logcat for additional info... It is very android specific. Can you install downloaded package by hand from phone (perhaps from file manager)? May be permissions problem? – Jan 07 '17 at 08:18
-
@MeysamIzadmehr did you solved the issue? Were you able to launch the installer? – user567 Nov 16 '17 at 10:05
I know some time has passed, but @vovkasm answer is outdated for a long time. You can achieve what you want with rn-fetch-blob
Thats what I did in my app - download .apk from url and than auto-run installation once the download is completed, that updates the app for new version.
It provides both: downloading and opening the file.
Keep in mind that for android 8+ this requires additional signed permission for REQUEST_INSTALL_PACKAGES
in manifest, but except that all works properly.
Simple example of opening the .apk with action view intent once its downloaded:
RNFetchBlob.android.actionViewIntent(
resource.path(), //path where the file is downloaded
"application/vnd.android.package-archive",
)
Also as @vovkasm wrote, it is still possible to download files using react-native-fs
, not sure about reading .apk tho.
What I have noticed is that react-native-fs
handles no connection errors and download progress, which doesn't work on rn-fetch-blob
, but on the other hand rn-fetch-blob
supports download manager while react-native-fs
doesnt... You can always mix both depending on what you need :)
Yes, you can do it. https://github.com/mikehardy/react-native-update-apk
1-Create Updater.js root directory and edit fileProviderAuthority as your package name + .provider
import {Alert} from 'react-native';
import * as UpdateAPK from 'rn-update-apk';
export default (onStart, onComp) => {
const update = new UpdateAPK.UpdateAPK({
iosAppId: '1104809018',
apkVersionUrl: 'https://example.com/apk/test-version.json',
//Must have test version json file and apk file to the remote server. You can find the contents of the Json file in the repo on the link and examine it.
fileProviderAuthority: 'com.lorien.provider',
needUpdateApp: (needUpdate) => {
needUpdate(true);
},
forceUpdateApp: () => {
console.log('forceUpdateApp callback called');
},
notNeedUpdateApp: () => {
console.log('notNeedUpdateApp callback called');
},
downloadApkStart: () => {
console.log('downloadApkStart callback called');
},
downloadApkProgress: (progress) => {
console.log(`downloadApkProgress callback called - ${progress}%...`);
onStart(progress);
},
downloadApkEnd: () => {
console.log('downloadApkEnd callback called');
onComp();
},
onError: (err) => {
console.log('onError callback called', err);
Alert.alert('There was an error', err.message);
},
});
update.checkUpdate();
};
2- Add libraries and add files
npm install rn-update-apk
(You may need to replace it if you get an error. Find the library in react_modules and change this line as import change tandroidx.core.content.FileProvider)
npm install react-native-fs
npm install react-native-exit-app
npm install react-native-simple-dialogs
Add files
go android>app>src>main>res
create a folder named xml
and create a js file named filepaths.xml in xml folder like this:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="cache" path="/" />
</paths>
3- Edit Android Manifest like this: (focus the xmlns line, permissions and provider tag)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lorien"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<!-- you might need the tools:replace thing to workaround rn-fetch-blob or other definitions of provider -->
<!-- just make sure if you "replace" here that you include all the paths you are replacing *plus* the cache path we use -->
<meta-data tools:replace="android:resource"
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
</manifest>
4- Using and call the UPDATER in main js:
import { Dialog } from 'react-native-simple-dialogs';
import RNExitApp from 'react-native-exit-app';
import Updater from '../Updater';
import { ActivityIndicator, Alert } from 'react-native';
constructor(props) {
super(props);
this.state = {
progressVisibility: false,
downloadVisibility: false,
downloadBar: "",
}
}
componentDidMount() {
console.disableYellowBox = true;
const self = this;
function onStart(progress) {
self.setState({downloadVisibility: true})
self.setState({downloadBar: progress})
}
function onComp() {
self.setState({downloadVisibility: false})
Alert.alert('Dikkat!','Gelen güncellemeyi yüklemeden işlem yapamazsınız. Yükleme işlemini başlatmadıysanız, uygulamayı kapatıp açarak tekrar deneyiniz.',[{ text: "Kapat", onPress: () => RNExitApp.exitApp() }])
}
Updater(onStart, onComp);
}

- 4,832
- 5
- 27
- 33