Step by Step membuat aplikasi android webview support download dan share di android studio
1. Langkah pertama
Gambar 1 . buat projek baru |
Pada gambar diatas silahkan plih "Empty Views Activity" kenapa harus ini? karena kita akan mencustom projek sesuai dengan keinginan kita, setelah itu pilih next nanti sesuaikan dengan bahasa program bahasa yang ada dan pastikan kamu pilih bahasa "JAVA" ya.
Gambar 2. Settingan projek dan nama projek Biarkan projek prosees build setelah berhasil maka akan muncul tampilan sebagai berikut |
2. Langka kedua
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:allowClearUserDataOnFailedRestore="true"
android:enabled="true"
android:extractNativeLibs="true"
android:hardwareAccelerated="true"
android:allowAudioPlaybackCapture="true"
android:uiOptions="splitActionBarWhenNarrow"
android:allowBackup="true"
android:allowClearUserData="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@drawable/logoapk"
android:label="@string/app_name"
android:roundIcon="@drawable/logoapk"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="user"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
3. Langkah Ketiga
package com.javasetid;
import android.Manifest;
import android.app.DownloadManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.webkit.PermissionRequest;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.ProgressBar;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private ProgressBar progressBar;
private ImageView loadingSpinner;
private SwipeRefreshLayout swipeRefreshLayout;
private ValueCallback<Uri[]> uploadMessage;
private View customView;
private WebChromeClient.CustomViewCallback customViewCallback;
private final ActivityResultLauncher<Intent> fileChooserLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (uploadMessage != null) {
Uri[] resultData = WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), result.getData());
uploadMessage.onReceiveValue(resultData);
uploadMessage = null;
}
}
);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
webView = findViewById(R.id.webView);
progressBar = findViewById(R.id.progressBar);
loadingSpinner = findViewById(R.id.loadingSpinner);
swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout);
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setAllowContentAccess(true);
webSettings.setMediaPlaybackRequiresUserGesture(false);
webSettings.setUserAgentString("Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Mobile Safari/537.36");
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
// Cek apakah URL adalah email atau aplikasi eksternal
if (isExternalApp(url)) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
return false;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
progressBar.setVisibility(View.VISIBLE);
startLoadingAnimation();
loadingSpinner.setVisibility(View.VISIBLE);
}
@Override
public void onPageFinished(WebView view, String url) {
progressBar.setVisibility(View.GONE);
stopLoadingAnimation();
loadingSpinner.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
}
});
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources());
}
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
fileChooserLauncher.launch(intent);
return true;
}
@Override
public void onShowCustomView(View view, CustomViewCallback callback) {
if (customView != null) {
callback.onCustomViewHidden();
return;
}
customView = view;
customViewCallback = callback;
ViewGroup decor = (ViewGroup) getWindow().getDecorView();
decor.addView(customView, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
@Override
public void onHideCustomView() {
if (customView == null) return;
ViewGroup decor = (ViewGroup) getWindow().getDecorView();
decor.removeView(customView);
customView = null;
customViewCallback.onCustomViewHidden();
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
}
});
webView.setDownloadListener((url, userAgent, contentDisposition, mimeType, contentLength) -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
return;
}
}
downloadFile(url, mimeType, contentDisposition);
});
webView.loadUrl("https://www.google.com");
swipeRefreshLayout.setOnRefreshListener(() -> webView.reload());
}
private boolean isExternalApp(String url) {
return url.startsWith("whatsapp://") ||
url.startsWith("fb://") ||
url.startsWith("twitter://") ||
url.startsWith("vnd.youtube:") ||
url.startsWith("tg://") || // Telegram
url.startsWith("shopee://") || // Shopee
url.startsWith("tokopedia://") || // Tokopedia
url.startsWith("market://") || // Google Play Store
url.startsWith("https://play.google.com/store/") ||
url.startsWith("geo:") || // Google Maps
url.startsWith("https://maps.google.com/") ||
url.startsWith("snssdk1233://") || // TikTok
url.startsWith("snssdk1180://") ||
url.startsWith("mailto:"); // Email
}
private void startLoadingAnimation() {
RotateAnimation rotate = new RotateAnimation(0, 360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(1000);
rotate.setRepeatCount(Animation.INFINITE);
loadingSpinner.startAnimation(rotate);
}
private void stopLoadingAnimation() {
loadingSpinner.clearAnimation();
}
private void downloadFile(String url, String mimeType, String contentDisposition) {
String fileName = "downloaded_file";
if (contentDisposition != null && contentDisposition.contains("filename=")) {
fileName = contentDisposition.substring(contentDisposition.indexOf("filename=") + 9).replaceAll("\"", "").trim();
}
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setMimeType(mimeType);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, fileName);
DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
dm.enqueue(request);
}
@Override
public void onBackPressed() {
if (webView.canGoBack()) {
webView.goBack();
} else {
super.onBackPressed();
}
}
}
4. Langkah ke Empat
gambar 4. bagian res projek |
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="3000"
android:repeatCount="infinite"/>
5. langkah Kelima
Gambar 5. folder yang telah diisi logo |
6. Langkah Keenam
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone" />
<ImageView
android:id="@+id/loadingSpinner"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:src="@drawable/loading"
android:visibility="gone" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/black"
app:titleTextColor="@color/black"
android:fitsSystemWindows="true"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" />
7. Langkah Ketujuh
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="blue">#00B2C9</color>
<!-- Teal Theme Colors -->
<color name="colorPrimaryTeal">#008577</color>
<color name="colorPrimaryDarkTeal">#00574B</color>
<color name="colorAccentTeal">#D81B60</color>
<!-- Cyan Theme Colors -->
<color name="colorPrimaryCyan">#26c6da</color>
<color name="colorPrimaryDarkCyan">#0095a8</color>
<color name="colorAccentCyan">#ffca28</color>
<color name="indigo">#3F51B5</color>
<color name="indigoDark">#303F9F</color>
<color name="indigoAccent">#757de8</color>
<color name="pink">#e91e63</color>
<color name="pinkDark">#b0003a</color>
<color name="pinkAccent">#ff6090</color>
<color name="nocolor">#00404040</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
<color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color>
</resources>
8. Langkah Ke delapan
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/blue</item>
<item name="colorPrimaryVariant">@color/blue</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
9. Langkah ke sembilan
plugins {
alias(libs.plugins.android.application)
}
android {
namespace = "com.javasetid"
compileSdk = 35
defaultConfig {
applicationId = "com.javasetid"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation(libs.appcompat)
implementation(libs.material)
implementation(libs.activity)
implementation(libs.constraintlayout)
implementation (libs.swiperefreshlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
}
10. Langkah Kesepuluh
📌 Fitur yang Tersedia dalam Proyek Ini
Berikut adalah daftar lengkap fitur yang tersedia dalam proyek browser berbasis WebView ini:
🔹 1. Fitur Dasar WebView
✅ Menampilkan halaman web di dalam aplikasi.
✅ Mendukung JavaScript (aktif secara default).
✅ Mendukung DOM Storage untuk penyimpanan data di dalam browser.
✅ Memuat User-Agent khusus agar lebih kompatibel dengan situs web modern.
✅ Mendukung navigasi ke halaman sebelumnya dengan tombol back.
🔹 2. Fitur Tampilan & Navigasi
✅ Menampilkan indikator loading saat halaman dimuat.
✅ Swipe to Refresh – Pengguna dapat menarik ke bawah untuk memuat ulang halaman.
✅ Mendukung tampilan layar penuh (fullscreen video).
✅ Mendukung tampilan landscape bahkan saat orientasi layar dikunci.
✅ Mendukung mode potret dan landscape tanpa stuck di mode potret.
✅ Memblokir pop-up agar dibuka di tab baru dalam aplikasi.
🔹 3. Fitur Download & Upload File
✅ Mendukung unduhan file menggunakan Download Manager bawaan Android.
✅ Otomatis memberi nama file saat diunduh.
✅ Mendukung unggahan file dari WebView.
✅ Mendukung akses ke penyimpanan perangkat untuk mengunggah file.
🔹 4. Fitur Pembukaan Aplikasi Eksternal
- YouTube
- Telegram
- Shopee
- Tokopedia
- Google Play Store
- Google Maps
- TikTok
Posting Komentar