Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 0 additions & 39 deletions .github/cocoapods-deploy.yml

This file was deleted.

4 changes: 4 additions & 0 deletions app/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/app

## [8.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@8.1.0...@capacitor/app@8.1.1) (2026-07-15)

**Note:** Version bump only for package @capacitor/app

# [8.1.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/app@8.0.1...@capacitor/app@8.1.0) (2026-03-25)

### Features
Expand Down
4 changes: 4 additions & 0 deletions browser/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/browser

## [8.0.4](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/browser@8.0.3...@capacitor/browser@8.0.4) (2026-07-15)

**Note:** Version bump only for package @capacitor/browser

## [8.0.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/browser@8.0.2...@capacitor/browser@8.0.3) (2026-03-25)

**Note:** Version bump only for package @capacitor/browser
Expand Down
4 changes: 4 additions & 0 deletions device/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/device

## [8.0.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/device@8.0.2...@capacitor/device@8.0.3) (2026-07-15)

**Note:** Version bump only for package @capacitor/device

## [8.0.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/device@8.0.1...@capacitor/device@8.0.2) (2026-03-25)

**Note:** Version bump only for package @capacitor/device
Expand Down
4 changes: 4 additions & 0 deletions motion/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/motion

## [8.0.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/motion@8.0.0...@capacitor/motion@8.0.1) (2026-07-15)

**Note:** Version bump only for package @capacitor/motion

# [8.0.0](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/motion@8.0.0-beta.0...@capacitor/motion@8.0.0) (2025-12-08)

**Note:** Version bump only for package @capacitor/motion
Expand Down
4 changes: 4 additions & 0 deletions push-notifications/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/push-notifications

## [8.1.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@8.1.1...@capacitor/push-notifications@8.1.2) (2026-07-15)

**Note:** Version bump only for package @capacitor/push-notifications

## [8.1.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/push-notifications@8.1.0...@capacitor/push-notifications@8.1.1) (2026-05-15)

**Note:** Version bump only for package @capacitor/push-notifications
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,30 @@
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.service.notification.StatusBarNotification;
import androidx.core.app.NotificationCompat;
import com.getcapacitor.*;
import com.getcapacitor.annotation.CapacitorPlugin;
import com.getcapacitor.annotation.Permission;
import com.getcapacitor.annotation.PermissionCallback;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.messaging.CommonNotificationBuilder;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.ImageDownload;
import com.google.firebase.messaging.NotificationParams;
import com.google.firebase.messaging.RemoteMessage;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.json.JSONException;
import org.json.JSONObject;

Expand All @@ -30,6 +40,7 @@
)
public class PushNotificationsPlugin extends Plugin {

private static final int IMAGE_DOWNLOAD_TIMEOUT_SECONDS = 5;
static final String PUSH_NOTIFICATIONS = "receive";

public static Bridge staticBridge = null;
Expand Down Expand Up @@ -281,7 +292,7 @@ public void fireNotification(RemoteMessage remoteMessage) {
CommonNotificationBuilder.DisplayNotificationInfo notificationInfo =
CommonNotificationBuilder.createNotificationInfo(getContext(), getContext(), params, channelId, bundle);

notificationManager.notify(notificationInfo.tag, notificationInfo.id, notificationInfo.notificationBuilder.build());
showForegroundNotification(notificationInfo, notification.getImageUrl());
}
}
}
Expand All @@ -298,6 +309,61 @@ public void fireNotification(RemoteMessage remoteMessage) {
notifyListeners("pushNotificationReceived", remoteMessageData, true);
}

private void showForegroundNotification(CommonNotificationBuilder.DisplayNotificationInfo notificationInfo, Uri imageUrl) {
Runnable showNotification = () -> {
try {
applyNotificationImage(notificationInfo.notificationBuilder, imageUrl);
} catch (RuntimeException e) {
Logger.error("Unexpected error while applying notification image", e);
} finally {
notificationManager.notify(notificationInfo.tag, notificationInfo.id, notificationInfo.notificationBuilder.build());
}
};

if (Looper.myLooper() != Looper.getMainLooper()) {
showNotification.run();
return;
}

ExecutorService displayExecutor = Executors.newSingleThreadExecutor();
displayExecutor.execute(() -> {
try {
showNotification.run();
} finally {
displayExecutor.shutdown();
}
});
}

private void applyNotificationImage(NotificationCompat.Builder notificationBuilder, Uri imageUrl) {
if (imageUrl == null) {
return;
}

ImageDownload imageDownload = ImageDownload.create(imageUrl.toString());
if (imageDownload == null) {
return;
}

ExecutorService imageExecutor = Executors.newSingleThreadExecutor();
try {
imageDownload.start(imageExecutor);
Bitmap bitmap = Tasks.await(imageDownload.getTask(), IMAGE_DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS);
notificationBuilder.setLargeIcon(bitmap);
notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(bitmap).bigLargeIcon((Bitmap) null));
} catch (ExecutionException e) {
Logger.warn("Failed to download notification image: " + e.getCause());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Logger.warn("Notification image download was interrupted");
} catch (TimeoutException e) {
Logger.warn("Notification image download timed out");
} finally {
imageDownload.close();
imageExecutor.shutdownNow();
}
}

public static PushNotificationsPlugin getPushNotificationsInstance() {
if (staticBridge != null && staticBridge.getWebView() != null) {
PluginHandle handle = staticBridge.getPlugin("PushNotifications");
Expand Down
6 changes: 6 additions & 0 deletions share/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/share

## [8.0.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/share@8.0.1...@capacitor/share@8.0.2) (2026-09-16)

### Bug Fixes

- **share:** Add nonce validation to broadcast receiver on Android ([#2592](https://github.com/ionic-team/capacitor-plugins/issues/2592)) ([fa8ddfb](https://github.com/ionic-team/capacitor-plugins/commit/fa8ddfb4e671fa1c91e6d92c80512f09cfd3a335))

## [8.0.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/share@8.0.0...@capacitor/share@8.0.1) (2026-02-12)

### Bug Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,44 @@
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.json.JSONException;

@CapacitorPlugin(name = "Share")
public class SharePlugin extends Plugin {

private static final String NONCE_EXTRA_KEY = "_share_nonce";

private BroadcastReceiver broadcastReceiver;
private boolean stopped = false;
private boolean isPresenting = false;
private ComponentName chosenComponent;
private String expectedNonce;

@Override
public void load() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Validate nonce to prevent spoofing from other apps
// Reference: https://github.com/ionic-team/capacitor-plugins/pull/2592
String receivedNonce = intent.getStringExtra(NONCE_EXTRA_KEY);
if (receivedNonce == null || !receivedNonce.equals(expectedNonce)) {
// Reject broadcasts that don't have the correct nonce
return;
}

ComponentName component;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
chosenComponent = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName.class);
component = intent.getParcelableExtra(Intent.EXTRA_CHOSEN_COMPONENT, ComponentName.class);
} else {
chosenComponent = getParcelableExtraLegacy(intent, Intent.EXTRA_CHOSEN_COMPONENT);
component = getParcelableExtraLegacy(intent, Intent.EXTRA_CHOSEN_COMPONENT);
}

// Only clear nonce if we successfully got the component data
if (component != null) {
chosenComponent = component;
expectedNonce = null;
}
}
};
Expand All @@ -64,6 +83,7 @@ private void activityResult(PluginCall call, ActivityResult result) {
call.resolve(callResult);
}
isPresenting = false;
expectedNonce = null;
}

@PluginMethod
Expand Down Expand Up @@ -117,6 +137,12 @@ public void share(PluginCall call) {
if (files != null && files.length() != 0) {
shareFiles(files, intent, call);
}

// Generate a random nonce to prevent spoofing via exported receiver
expectedNonce = UUID.randomUUID().toString();
Intent callbackIntent = new Intent(Intent.EXTRA_CHOSEN_COMPONENT);
callbackIntent.putExtra(NONCE_EXTRA_KEY, expectedNonce);

int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flags = flags | PendingIntent.FLAG_MUTABLE;
Expand All @@ -126,7 +152,7 @@ public void share(PluginCall call) {
}

// requestCode parameter is not used. Providing 0
PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, new Intent(Intent.EXTRA_CHOSEN_COMPONENT), flags);
PendingIntent pi = PendingIntent.getBroadcast(getContext(), 0, callbackIntent, flags);
Intent chooser = Intent.createChooser(intent, dialogTitle, pi.getIntentSender());
chosenComponent = null;
chooser.addCategory(Intent.CATEGORY_DEFAULT);
Expand Down Expand Up @@ -180,6 +206,7 @@ private void shareFiles(JSArray files, Intent intent, PluginCall call) {

@Override
protected void handleOnDestroy() {
expectedNonce = null;
if (broadcastReceiver != null) {
getActivity().unregisterReceiver(broadcastReceiver);
}
Expand Down
26 changes: 21 additions & 5 deletions share/ios/Sources/SharePlugin/SharePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,28 @@ public class SharePlugin: CAPPlugin, CAPBridgedPlugin {
}

}
if self?.bridge?.viewController?.presentedViewController != nil {
call.reject("Can't share while sharing is in progress")
return
// Present from the topmost presented view controller so the share sheet appears
// above any view controller the app has presented over the webview. With nothing
// presented this resolves to the bridge view controller, i.e. unchanged behaviour.
// A share is only in progress when a share sheet is already presented.
var presenter = self?.bridge?.viewController
while let presented = presenter?.presentedViewController {
if presented is UIActivityViewController {
call.reject("Can't share while sharing is in progress")
return
}
presenter = presented
}
// `setCenteredPopover` anchors to the bridge view controller's view, which is not in
// the presenter's hierarchy when presenting from a different view controller. Anchor
// the popover to the presenting view controller's own view instead, centered and
// without an arrow, matching `setCenteredPopover` behaviour.
if let popover = actionController.popoverPresentationController, let presenterView = presenter?.view {
popover.sourceView = presenterView
popover.sourceRect = CGRect(x: presenterView.bounds.midX, y: presenterView.bounds.midY, width: 0, height: 0)
popover.permittedArrowDirections = []
}
self?.setCenteredPopover(actionController)
self?.bridge?.viewController?.present(actionController, animated: true, completion: nil)
presenter?.present(actionController, animated: true, completion: nil)
}
}
}
4 changes: 4 additions & 0 deletions splash-screen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

- **splash-screen:** implement launchFadeOutDuration support on iOS ([#2524](https://github.com/ionic-team/capacitor-plugins/issues/2524)) ([d1b094d](https://github.com/ionic-team/capacitor-plugins/commit/d1b094d52153bf4c2d219c5ee3315aea22ef4e1e))

## [8.0.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@8.0.1...@capacitor/splash-screen@8.0.2) (2026-07-15)

**Note:** Version bump only for package @capacitor/splash-screen

## [8.0.1](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/splash-screen@8.0.0...@capacitor/splash-screen@8.0.1) (2026-02-12)

### Bug Fixes
Expand Down
4 changes: 4 additions & 0 deletions status-bar/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline

**Note:** Version bump only for package @capacitor/status-bar

## [8.0.3](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/status-bar@8.0.2...@capacitor/status-bar@8.0.3) (2026-07-15)

**Note:** Version bump only for package @capacitor/status-bar

## [8.0.2](https://github.com/ionic-team/capacitor-plugins/compare/@capacitor/status-bar@8.0.1...@capacitor/status-bar@8.0.2) (2026-03-25)

### Bug Fixes
Expand Down
Loading