Skip to content

Commit fed9fe0

Browse files
committed
fix installer
1 parent 3f2f6cb commit fed9fe0

File tree

4 files changed

+113
-13
lines changed

4 files changed

+113
-13
lines changed

app/src/main/AndroidManifest.xml

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools">
4-
<!-- AndroidManifest.xml -->
4+
<!-- Permissions -->
55
<uses-permission android:name="android.permission.INTERNET" />
66
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
77
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
88
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
9+
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
10+
911
<application
1012
android:allowBackup="true"
1113
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -16,6 +18,8 @@
1618
android:supportsRtl="true"
1719
android:theme="@style/Theme.LudditeInstaller"
1820
tools:targetApi="31">
21+
22+
<!-- File Provider for sharing APK files -->
1923
<provider
2024
android:name="androidx.core.content.FileProvider"
2125
android:authorities="${applicationId}.provider"
@@ -25,14 +29,14 @@
2529
android:name="android.support.FILE_PROVIDER_PATHS"
2630
android:resource="@xml/file_paths" />
2731
</provider>
32+
2833
<activity
2934
android:name=".MainActivity"
3035
android:exported="true"
3136
android:label="@string/app_name"
3237
android:theme="@style/Theme.LudditeInstaller">
3338
<intent-filter>
3439
<action android:name="android.intent.action.MAIN" />
35-
3640
<category android:name="android.intent.category.LAUNCHER" />
3741
</intent-filter>
3842
</activity>

app/src/main/java/com/example/ludditeinstaller/AppStore.java

+90-10
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,18 @@ private Uri downloadApk(Context context, String apkUrl, String fileName) {
7272
try {
7373
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
7474
request.setTitle(fileName);
75+
76+
// Ensure the download directory exists
77+
File downloadDir = context.getExternalFilesDir(DOWNLOADS_DIR);
78+
if (downloadDir != null && !downloadDir.exists()) {
79+
downloadDir.mkdirs();
80+
logDisplay.log(TAG, "Created download directory: " + downloadDir.getAbsolutePath());
81+
}
82+
83+
// Set the destination (external app files directory)
7584
request.setDestinationInExternalFilesDir(context, DOWNLOADS_DIR, fileName);
85+
logDisplay.log(TAG, "Download destination: " + context.getExternalFilesDir(DOWNLOADS_DIR).getAbsolutePath() + "/" + fileName);
86+
7687
request.setAllowedOverMetered(true);
7788
request.setAllowedOverRoaming(true);
7889
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
@@ -103,7 +114,45 @@ private Uri downloadApk(Context context, String apkUrl, String fileName) {
103114
if (uriIndex != -1) {
104115
String uriString = cursor.getString(uriIndex);
105116
cursor.close();
106-
return Uri.parse(uriString);
117+
118+
Uri downloadedUri = Uri.parse(uriString);
119+
logDisplay.log(TAG, "Downloaded file URI: " + downloadedUri.toString());
120+
121+
// If it's a content URI, try to get the actual file path
122+
if (downloadedUri.getScheme() != null && downloadedUri.getScheme().equals("content")) {
123+
logDisplay.log(TAG, "Downloaded file is a content URI");
124+
125+
// Try to get the actual file path using the download manager
126+
try {
127+
DownloadManager.Query fileQuery = new DownloadManager.Query();
128+
fileQuery.setFilterById(downloadId);
129+
Cursor filePathCursor = dm.query(fileQuery);
130+
131+
if (filePathCursor.moveToFirst()) {
132+
int fileNameIdx = filePathCursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
133+
if (fileNameIdx != -1) {
134+
String filePath = filePathCursor.getString(fileNameIdx);
135+
filePathCursor.close();
136+
137+
if (filePath != null) {
138+
File file = new File(filePath);
139+
logDisplay.log(TAG, "Actual file path: " + file.getAbsolutePath() + ", exists: " + file.exists());
140+
if (file.exists()) {
141+
return Uri.fromFile(file);
142+
}
143+
}
144+
} else {
145+
filePathCursor.close();
146+
}
147+
} else {
148+
filePathCursor.close();
149+
}
150+
} catch (Exception e) {
151+
logDisplay.log(TAG, "Error getting file path: " + e.getMessage());
152+
}
153+
}
154+
155+
return downloadedUri;
107156
}
108157
} else if (status == DownloadManager.STATUS_FAILED) {
109158
cursor.close();
@@ -169,16 +218,47 @@ private String getReasonString(int reason) {
169218

170219
private void installApk(Context context, Uri fileUri) {
171220
try {
221+
logDisplay.log(TAG, "Preparing installation from URI: " + fileUri);
172222
File file = new File(fileUri.getPath());
173-
Uri contentUri = FileProvider.getUriForFile(context,
174-
context.getPackageName() + ".provider",
175-
file);
176-
177-
Intent intent = new Intent("com.luddite.app.store.INSTALL_PACKAGE");
178-
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
179-
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
180-
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
181-
context.startActivity(intent);
223+
224+
logDisplay.log(TAG, "File exists: " + file.exists() + ", path: " + file.getAbsolutePath());
225+
226+
// Check if the file is a direct path or content URI
227+
Uri contentUri;
228+
if (fileUri.getScheme() != null && fileUri.getScheme().equals("content")) {
229+
contentUri = fileUri;
230+
logDisplay.log(TAG, "Using direct content URI: " + contentUri);
231+
} else {
232+
contentUri = FileProvider.getUriForFile(context,
233+
context.getPackageName() + ".provider",
234+
file);
235+
logDisplay.log(TAG, "Created content URI using FileProvider: " + contentUri);
236+
}
237+
238+
// First try the custom intent
239+
try {
240+
Intent customIntent = new Intent("com.luddite.app.store.INSTALL_PACKAGE");
241+
customIntent.setDataAndType(contentUri, "application/vnd.android.package-archive");
242+
customIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
243+
customIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
244+
logDisplay.log(TAG, "Attempting to start custom intent: com.luddite.app.store.INSTALL_PACKAGE");
245+
context.startActivity(customIntent);
246+
} catch (Exception e) {
247+
logDisplay.log(TAG, "Custom intent failed: " + e.getMessage() + ". Trying standard install intent...");
248+
249+
// Fallback to standard package installer
250+
Intent standardIntent = new Intent(Intent.ACTION_VIEW);
251+
standardIntent.setDataAndType(contentUri, "application/vnd.android.package-archive");
252+
standardIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
253+
standardIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
254+
logDisplay.log(TAG, "Starting standard install intent: ACTION_VIEW");
255+
context.startActivity(standardIntent);
256+
}
257+
258+
// Notify completion - we consider it complete when installation dialog starts
259+
if (callback != null) {
260+
callback.onDownloadComplete();
261+
}
182262
} catch (Exception e) {
183263
logDisplay.log(TAG, "Error in installApk: " + e.getMessage());
184264
if (callback != null) {

app/src/main/java/com/example/ludditeinstaller/MainActivity.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class MainActivity : AppCompatActivity(), AppStore.AppStoreCallback {
9393
private fun updateButtons(apps: List<ApkFile>) {
9494
apps.forEach { app ->
9595
val button = Button(this).apply {
96-
text = "${app.name} v${app.version}"
96+
text = if (app.version.isNotEmpty()) "${app.name} v${app.version}" else app.name
9797
layoutParams = LinearLayout.LayoutParams(
9898
ViewGroup.LayoutParams.MATCH_PARENT,
9999
ViewGroup.LayoutParams.WRAP_CONTENT

app/src/main/res/xml/file_paths.xml

+16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<paths xmlns:android="http://schemas.android.com/apk/res/android">
3+
<!-- Allow FileProvider to serve files from the app's external files directory -->
34
<external-files-path
45
name="apks"
56
path="apk_downloads" />
7+
8+
<!-- Allow access to all external storage -->
9+
<external-path
10+
name="external_files"
11+
path="." />
12+
13+
<!-- Allow access to internal storage -->
14+
<files-path
15+
name="internal_files"
16+
path="." />
17+
18+
<!-- Allow access to cache directory -->
19+
<cache-path
20+
name="cache"
21+
path="." />
622
</paths>

0 commit comments

Comments
 (0)