Skip to content

Conversation

@hflexgrig
Copy link
Contributor

@hflexgrig hflexgrig commented Aug 3, 2025

Uses app group to store image data from extension, opens the main app by custom url scheme, and the main app reads and displays image (from photos or screenshot editor)

Summary by CodeRabbit

  • New Features

    • Enabled sharing images from the iOS Share Extension directly to the main app using a custom URL scheme.
    • Images shared via the extension are now displayed in the main app automatically.
  • Improvements

    • Enhanced data sharing security and reliability with updated app group entitlements.
    • Improved image loading performance by directly setting image data in the main app.
  • Bug Fixes

    • Improved image handling and loading between the extension and the main app.
  • Chores

    • Updated SDK version and configuration files for compatibility and entitlements.

Copy link

@accesslint accesslint bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are accessibility issues in these changes.

@coderabbitai
Copy link

coderabbitai bot commented Aug 3, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

This update implements cross-process image sharing between an iOS Share Extension and its main app container using an app group and a custom URL scheme. It introduces new entitlements, modifies the UI and control flow to load and display shared images, and updates project and configuration files to support secure data transfer and inter-app communication.

Changes

Cohort / File(s) Change Summary
SDK Version Update
global.json
Updated the .NET SDK version from 9.0.300 to 9.0.303.
App Container Logic & UI
iOSExtensions/ShareExtension/AppContainer/App.xaml.cs,
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml,
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
Added a private readonly MainPage instance in App. Changed CreateWindow to use this instance. Added public LoadImage(byte[] imageData) methods in both App and MainPage to load images from byte arrays. Modified MainPage.xaml to name the Image control as Img.
iOS AppDelegate & Configuration
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs,
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist,
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
Added override of OpenUrl in AppDelegate to handle custom URL scheme "mauiapp" and load shared image data from app group user defaults. Updated Info.plist to register the "mauiapp" URL scheme. Added Entitlements.plist to declare the app group entitlement for shared data access.
Share Extension Logic
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs
Modified DidSelectPost to be async and export the shared image to the main app by saving it to the app group user defaults. Added methods to load the image asynchronously, open the main app via custom URL scheme, and complete the extension. Introduced constants for app group identifier and shared image key. Improved error handling and asynchronous flow.
Share Extension Entitlements & Project
iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist,
iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
Added app group entitlement to the extension's entitlements plist. Updated the project file to include the entitlements plist for code signing and resource inclusion.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ShareExtension
    participant AppGroupStorage
    participant MainApp
    participant AppDelegate
    participant MainPage

    User->>ShareExtension: Shares an image
    ShareExtension->>ShareExtension: ExportImageToMainApp()
    ShareExtension->>AppGroupStorage: Save image as "shared_image"
    ShareExtension->>MainApp: Open custom URL (mauiapp://openFromShare)
    MainApp->>AppDelegate: AppDelegate.OpenUrl(...)
    AppDelegate->>AppGroupStorage: Retrieve "shared_image"
    AppDelegate->>MainApp: Call LoadImage(byte[] imageData)
    MainApp->>MainPage: LoadImage(byte[] imageData)
    MainPage->>MainPage: Display image
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

A bunny hops from app to share,
Passing images through digital air.
With entitlements set and URLs in tow,
The picture appears—watch it glow!
From extension to main, the journey is swift,
In a hop and a byte, we share and uplift.
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5dce21 and 0de8272.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • global.json
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
🧰 Additional context used
🪛 GitHub Check: Codacy Static Code Analysis
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs

[warning] 39-39: iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs#L39
Return 'Task' instead.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (6)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (2)

10-13: LGTM! Constants properly extracted from magic strings.

The extraction of magic strings into well-named constants addresses previous feedback and improves maintainability.


17-48: Excellent implementation with comprehensive error handling.

This implementation addresses all previous feedback concerns:

  • ✅ Proper error handling with try-catch
  • ✅ Data validation with length checks
  • ✅ Cleanup of shared data after successful read
  • ✅ Appropriate return values based on success/failure
  • ✅ Delegates to base implementation for non-matching URLs
  • ✅ Uses constants instead of magic strings

The code is well-structured and production-ready.

iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (4)

9-11: LGTM! Constants properly defined.

The constants are well-named and address previous feedback about hardcoded values throughout the codebase.


39-53: Acceptable async void implementation given override constraints.

While static analysis correctly flags async void as problematic, this is an override method that cannot change its signature. The implementation properly handles this constraint with comprehensive error handling and ensures CompleteExtension() is always called in the finally block.


115-147: LGTM! Robust URL opening with iOS version compatibility.

The implementation properly handles different iOS versions and ensures the extension completes correctly in all code paths. The responder chain traversal is a solid approach to find the UIApplication instance.


149-152: LGTM! Clean abstraction for extension completion.

The method provides a clear abstraction and uses modern C# syntax with the empty array literal.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🔭 Outside diff range comments (1)
iOSExtensions/ShareExtension/log.txt (1)

1-48: Remove log file from version control.

This log file should not be committed to the repository as it:

  1. Contains sensitive development environment information (simulator device paths)
  2. Will continuously change during development, causing unnecessary version control noise
  3. Can grow large over time

Add this file to .gitignore and remove it from the repository:

+# Log files
+*.log
+log.txt

Consider implementing structured logging with appropriate log levels instead of verbose console output for production code.

🧹 Nitpick comments (8)
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (2)

12-16: Improve image rendering for arbitrary sizes

Setting Aspect="AspectFit" prevents distortion when loading screenshots or photos of unknown dimensions.

-            <Image x:Name="Img"
-                Source="dotnet_bot.png"
-                SemanticProperties.Description="Cute dot net bot waving hi to you!"
-                HeightRequest="200"
-                HorizontalOptions="Center" />
+            <Image x:Name="Img"
+                Source="dotnet_bot.png"
+                SemanticProperties.Description="Placeholder image"
+                HeightRequest="200"
+                Aspect="AspectFit"
+                HorizontalOptions="Center" />

18-24: Remove dead commented-out controls to keep XAML clean

If the label/button are no longer needed, deleting them avoids noise and reduces merge-conflict surface.

-            <!-- <Label Text="Click button to open Safari. Then click on Share button"
-                   HorizontalOptions="Center"/>
-
-            <Button
-                Text="Open Safari"
-                Clicked="OnClicked"
-                HorizontalOptions="Center" /> -->
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1)

35-45: Consider using a more specific URL scheme for security.

The URL scheme mauiapp is fairly generic and could potentially be registered by other apps, leading to URL interception. Consider using a more specific scheme that includes your company or app identifier, such as vladislavantonyuk-mauiapp or com-vladislavantonyuk-container.

-            <key>CFBundleURLName</key>
-            <string>com.vladislavantonyuk.container</string>
-            <key>CFBundleURLSchemes</key>
-            <array>
-                <string>mauiapp</string>
-            </array>
+            <key>CFBundleURLName</key>
+            <string>com.vladislavantonyuk.container</string>
+            <key>CFBundleURLSchemes</key>
+            <array>
+                <string>com-vladislavantonyuk-container</string>
+            </array>
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1)

15-18: Remove commented code.

The commented-out OnClicked method should be removed rather than left in the codebase. Version control maintains the history if needed.

-	// private async void OnClicked(object sender, EventArgs e)
-	// {
-	// 	await Launcher.OpenAsync("https://vladislavantonyuk.github.io/");
-	// }
iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (2)

5-8: Consider following standard naming conventions.

While the warning suppression works, consider following standard C# naming conventions where private fields use underscore prefix. The current naming is actually correct for private fields.

You can remove the warning suppression as _mainPage follows standard conventions:

-#pragma warning disable IDE1006 // Naming Styles

 private MainPage _mainPage;
-#pragma warning restore IDE1006 // Naming Styles

10-12: Remove excessive blank lines.

Multiple consecutive blank lines reduce code readability.

-


-
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2)

29-35: Remove commented-out code

The commented code adds clutter and appears to be an alternative implementation that's not being used.


69-108: Extension only processes first image attachment

The loop iterates through all attachments but returns after processing the first image. Consider processing all images or documenting this limitation.

Would you like me to implement support for multiple image attachments?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bcabe43 and a3f4b45.

📒 Files selected for processing (12)
  • MauiSamples.sln (1 hunks)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2 hunks)
  • iOSExtensions/ShareExtension/log.txt (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (3)
iOSExtensions/ShareExtension/AppContainer/MauiProgram.cs (1)
  • MauiProgram (3-12)
iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (3)
  • App (3-29)
  • App (13-18)
  • LoadImage (25-28)
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1)
  • LoadImage (10-13)
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1)
iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1)
  • LoadImage (25-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (6)
global.json (1)

3-3: Confirm build agents have .NET 9.0.303

The patch-level bump is harmless for local dev, but CI images and hosted agents must also have 9.0.303; otherwise the build will fall back to an older SDK and ignore allowPrerelease, giving surprising results.
Please double-check the pipeline pool or Dev Container definition.

iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1)

8-10: Only a formatting change – looks fine

The added blank line does not affect MSBuild evaluation. No further action required.

iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1)

5-8: App-group entitlement added – verify it matches the provisioning profile

group.com.yourcompany.mauiapp must already exist in the Apple Developer portal and be included in both the app’s and extension’s provisioning profiles. A mismatch will cause runtime failures when accessing the shared container.

iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1)

5-8: Consistent group ID – good, but ensure portal / profile alignment

The group ID matches the extension’s plist, which is required. Just make sure the same entitlement is enabled for the main-app App ID and its provisioning profile before TestFlight / App Store submission.

iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1)

5-5: LGTM!

The UIKit using statement is correctly added and necessary for the iOS-specific types used in the OpenUrl method.

MauiSamples.sln (1)

1-406: LGTM!

The solution file properly includes the ShareExtension projects and maintains a well-organized structure with appropriate project nesting.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements image sharing functionality from an iOS Share Extension to a main MAUI app. When users share images from the iOS Photos app or screenshot editor, the extension saves the image data to a shared app group and opens the main app via a custom URL scheme. The main app then retrieves and displays the shared image.

  • Added iOS Share Extension project with image processing and app group communication
  • Implemented custom URL scheme handling in the main app to receive shared images
  • Added app group entitlements to both extension and main app for secure data sharing

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ShareViewController.cs Implements core image sharing logic with async processing and URL scheme launching
AppDelegate.cs Handles custom URL scheme and retrieves shared image data from app group
MainPage.xaml.cs Adds method to display shared images in the UI
Info.plist Configures custom URL scheme for the main app
Entitlements.plist (both) Enables app group access for data sharing between extension and app
App.xaml.cs Manages shared MainPage instance for image display
log.txt Debug logging output from extension testing
global.json Updates SDK version
MauiSamples.sln Adds new Visual Studio solution structure
Comments suppressed due to low confidence (1)

iOSExtensions/ShareExtension/AppContainer/App.xaml.cs:5

  • [nitpick] The pragma warning disable suggests a naming convention issue with the _mainPage field. Consider following proper C# naming conventions instead of suppressing the warning.
#pragma warning disable IDE1006 // Naming Styles

@VladislavAntonyuk
Copy link
Owner

@hflexgrig thank you for the PR.
Could you please keep the previous Safari url sharing untouched and keep both image sharing and safari sharing working in the app?
Also please address the comments left by Copilot, there are some potential issues.
And finally clean up the files like logs and MauiSample.sln. I use new slnx format.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (6)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (6)

41-49: Avoid async void in override methods

Using async void in an override method can lead to unhandled exceptions and unpredictable behavior.


82-82: Add return statement after setting task result to false

Missing return statement after setting task result, causing execution to continue.


84-85: Extract app group identifier to configuration

The app group identifier is hardcoded and should be configurable.


131-138: Add support for iOS versions below 18

The current implementation only works on iOS 18+ and returns false for older versions, breaking the feature for most users.


150-150: Use Array.Empty() for better performance

Use Array.Empty<NSExtensionItem>() instead of new NSExtensionItem[0] for better performance and consistency with modern C# practices.


106-111: Improve error handling in catch block

The catch block has an empty implementation with just a comment, and the method returns true even when an exception occurs, masking failures from callers.

		}
-		catch (System.Exception)
+		catch (System.Exception ex)
		{
-			//log ex
+			// Log the exception properly
+			System.Diagnostics.Debug.WriteLine($"Error in ExportImageToMainApp: {ex}");
+			return false;
		}
-
-		return true;
+		
+		return true;
🧹 Nitpick comments (2)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2)

1-1: Remove unused deprecated import

The MobileCoreServices framework is deprecated since iOS 14 and appears to be unused in this file. The code already uses UniformTypeIdentifiers for type checking.

-using MobileCoreServices;
using Social;

27-32: Remove commented placeholder code

Commented-out code should be removed. If this is intended as documentation for future implementation, consider adding it to the project documentation instead.

-		//If you extend from UIViewController, instead of SLComposeServiceViewController, add image loading logic here.
-		// var flowControl = await ExportImageToMainApp();
-		// if (!flowControl)
-		// {
-		// 	return;
-		// }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3f4b45 and 8ab8e60.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • global.json
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (6)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (6)

41-49: Avoid async void in override methods.

Using async void in an override method can lead to unhandled exceptions and unpredictable behavior. iOS may not wait for the async operation to complete.


70-96: Multiple unaddressed issues in image loading logic.

Several previously identified issues remain unaddressed:

  1. Missing return statement: After TrySetResult(false), execution continues and may call TrySetResult(true).
  2. Hardcoded app group identifier: Should be extracted to a constant.
  3. Unsafe null-forgiving operator: Using data! without proper null checking.

Apply these fixes:

+private const string APP_GROUP_IDENTIFIER = "group.com.yourcompany.mauiapp";

 if (itemProvider.HasItemConformingTo(UniformTypeIdentifiers.UTTypes.Image.ToString()))
 {
   itemProvider.LoadItem(UniformTypeIdentifiers.UTTypes.Image.ToString(), null, (nsObject, error) =>
   {
     NSData? data = null;

     if (nsObject is NSUrl url)//from photos
     {
       data = NSData.FromUrl(url);
     }
     else if (nsObject is UIImage uiImage)//from screenshot editor
     {
       data = uiImage.AsPNG();
     }

-    if (data is null) tcs.TrySetResult(false);
+    if (data is null)
+    {
+      tcs.TrySetResult(false);
+      return;
+    }

-    var userDefaults = new NSUserDefaults("group.com.yourcompany.mauiapp", NSUserDefaultsType.SuiteName);
+    var userDefaults = new NSUserDefaults(APP_GROUP_IDENTIFIER, NSUserDefaultsType.SuiteName);
-    userDefaults.SetValueForKey(data!, new NSString("shared_image"));
+    userDefaults.SetValueForKey(data, new NSString("shared_image"));

109-115: Improve error handling - method masks failures.

The catch block doesn't properly handle errors and still returns true, which masks failures from callers.

 catch (System.Exception)
 {
   //log ex
+  return false;
 }

-return true;

134-141: Add support for iOS versions below 18.

The current implementation only works on iOS 18+ and returns false for older versions, effectively breaking the feature for most users.

Implement the fallback:

 else
 {
-  //TODO: fix for > ios18 versions
-  // var sel = new Selector("openURL:");
-  // var result = application.PerformSelector(sel, url, 0);
-  // return result != null;
-  return false;
+  var sel = new ObjCRuntime.Selector("openURL:");
+  var result = application.PerformSelector(sel, url, 0);
+  CompleteExtension();
+  return result != null;
 }

153-153: Use Array.Empty for better performance.

Use Array.Empty<NSExtensionItem>() instead of new NSExtensionItem[0] for better performance and consistency with modern C# practices.

-ExtensionContext?.CompleteRequest(new NSExtensionItem[0], null);
+ExtensionContext?.CompleteRequest(Array.Empty<NSExtensionItem>(), null);

51-67: Critical: Missing Safari URL sharing and null safety issues.

Multiple critical issues need to be addressed:

  1. Missing Safari URL sharing: Per PR objectives, this breaks existing Safari URL sharing functionality.
  2. Missing null checks: Code accesses ExtensionContext?.InputItems[0] without verifying the array exists and has elements.

Add Safari URL support and null checks:

 private async Task<bool> ExportImageToMainApp()
 {
   try
   {
     var tcs = new TaskCompletionSource<bool>();

+    if (ExtensionContext?.InputItems == null || ExtensionContext.InputItems.Length == 0)
+    {
+      CompleteExtension();
+      return false;
+    }

     var extensionItem = ExtensionContext?.InputItems[0] as NSExtensionItem;
     var attachments = extensionItem?.Attachments;

-    if (attachments is null)
+    if (attachments == null || attachments.Length == 0)
+    {
+      CompleteExtension();
       return false;
+    }

-    foreach (var itemProvider in attachments)
+    foreach (var itemProvider in attachments)
     {
+      // Handle URLs (for Safari sharing)
+      if (itemProvider.HasItemConformingTo(UTTypes.Url.ToString()))
+      {
+        itemProvider.LoadItem(UTTypes.Url.ToString(), null, (nsObject, error) =>
+        {
+          if (nsObject is NSUrl url)
+          {
+            var userDefaults = new NSUserDefaults(APP_GROUP_IDENTIFIER, NSUserDefaultsType.SuiteName);
+            userDefaults.SetString(url.AbsoluteString, new NSString("shared_url"));
+            userDefaults.Synchronize();
+            tcs.TrySetResult(true);
+          }
+          else
+          {
+            tcs.TrySetResult(false);
+          }
+        });
+        continue;
+      }
+
       if (itemProvider.HasItemConformingTo(UniformTypeIdentifiers.UTTypes.Image.ToString()))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab8e60 and d661e99.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • global.json
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (1)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (1)

26-32: LGTM! Helpful guidance for alternative implementation.

The commented code provides clear guidance for developers who might want to extend UIViewController instead of SLComposeServiceViewController.

@hflexgrig
Copy link
Contributor Author

@hflexgrig thank you for the PR. Could you please keep the previous Safari url sharing untouched and keep both image sharing and safari sharing working in the app? Also please address the comments left by Copilot, there are some potential issues. And finally clean up the files like logs and MauiSample.sln. I use new slnx format.

Done!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1)

12-12: Consider making app group identifier configurable.

While using a constant is better than a magic string, the app group identifier could be made configurable through app settings or build configuration to support different environments (dev, staging, production).

Consider reading from configuration:

private static string AppGroupIdentifier => 
    Microsoft.Maui.Controls.Application.Current?.Resources?["AppGroupIdentifier"]?.ToString() 
    ?? "group.com.yourcompany.mauiapp";
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b2a1cd and e392a28.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
🚧 Files skipped from review as they are similar to previous changes (8)
  • global.json
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (1)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1)

10-13: Good implementation of constants!

The constants are well-defined and address the previous feedback about avoiding magic strings. This improves maintainability and readability.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (5)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (5)

39-53: Async void override method still not addressed.

The past review comment about avoiding async void in override methods remains unaddressed. This can lead to unhandled exceptions and unpredictable behavior since iOS may not wait for the async operation to complete.

Consider the previously suggested approach using Task.Run or a synchronous method with completion handlers.


55-112: Safari URL sharing functionality still missing.

The method only handles image attachments and doesn't support URL attachments, which breaks the Safari URL sharing functionality as mentioned in the PR objectives. This was flagged in a past review comment with specific implementation guidance.

Please implement URL handling alongside image handling to maintain backward compatibility with Safari sharing.


62-63: Missing bounds check for InputItems access.

Accessing ExtensionContext?.InputItems[0] without checking if InputItems has any elements could cause an IndexOutOfRangeException.

Add a null and bounds check before accessing the first element.


87-90: Missing return statement after TrySetResult(false).

The code continues execution after setting the task result to false, which could lead to unexpected behavior including calling TrySetResult(true) later.

Add a return statement after tcs.TrySetResult(false); to prevent further execution.


146-149: Consider using Array.Empty() for better performance.

The past review comment suggested using Array.Empty<NSExtensionItem>() instead of [] for better performance and consistency with modern C# practices.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e392a28 and e267dd1.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
🚧 Files skipped from review as they are similar to previous changes (8)
  • global.json
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
🔇 Additional comments (2)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2)

1-3: LGTM! UniformTypeIdentifiers using statement added correctly.

This addresses the past review comment about the missing using statement for UniformTypeIdentifiers.


9-11: LGTM! Constants properly extracted from hardcoded values.

This addresses past review comments about extracting the hardcoded app group identifier and other magic strings into configurable constants.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (3)

39-53: Improved error handling, but async void remains a concern.

The addition of try-catch-finally block with CompleteExtension() in the finally block significantly improves error handling and ensures the extension context is always completed. However, the method remains async void, which can still lead to unhandled exceptions in the iOS runtime.

Note: The async void issue from previous reviews remains, but the error handling improvements make this much more robust.


87-91: Critical: Missing return statement after TrySetResult(false).

After calling tcs.TrySetResult(false) when data is null, the code continues execution and may call TrySetResult(true) later, causing unexpected behavior.

Apply this fix:

 if (data is null)
 {
 	tcs.TrySetResult(false);
+	return;
 }

70-100: Missing Safari URL sharing functionality.

The method only handles image attachments and ignores URL attachments, breaking the existing Safari URL sharing functionality mentioned in the PR objectives. Both image and URL sharing must be supported.

Add URL handling before the image handling:

 foreach (var itemProvider in attachments)
 {
+	// Handle URLs (for Safari sharing)
+	if (itemProvider.HasItemConformingTo(UTTypes.Url.ToString()))
+	{
+		itemProvider.LoadItem(UTTypes.Url.ToString(), null, (nsObject, _) =>
+		{
+			if (nsObject is NSUrl url)
+			{
+				var userDefaults = new NSUserDefaults(AppGroupIdentifier, NSUserDefaultsType.SuiteName);
+				userDefaults.SetString(url.AbsoluteString, new NSString("shared_url"));
+				userDefaults.Synchronize();
+				tcs.TrySetResult(true);
+			}
+			else
+			{
+				tcs.TrySetResult(false);
+			}
+		});
+		continue;
+	}
+
 	if (itemProvider.HasItemConformingTo(UTTypes.Image.ToString()))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e267dd1 and a5dce21.

📒 Files selected for processing (10)
  • global.json (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist (1 hunks)
  • iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml
  • global.json
  • iOSExtensions/ShareExtension/AppContainer/App.xaml.cs
  • iOSExtensions/ShareExtension/AppContainerExtension/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainerExtension/AppContainerExtension.csproj
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Entitlements.plist
  • iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs
  • iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/Info.plist
🧰 Additional context used
🧬 Code Graph Analysis (1)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (3)
iOSExtensions/ShareExtension/AppContainer/MauiProgram.cs (1)
  • MauiProgram (3-12)
iOSExtensions/ShareExtension/AppContainer/App.xaml.cs (3)
  • App (3-22)
  • App (7-11)
  • LoadImage (18-21)
iOSExtensions/ShareExtension/AppContainer/MainPage.xaml.cs (1)
  • LoadImage (10-13)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
iOSExtensions/ShareExtension/AppContainer/Platforms/iOS/AppDelegate.cs (1)

5-14: LGTM! Constants properly defined.

The addition of the UIKit using statement and private constants for URL scheme, host, app group identifier, and shared image key addresses previous feedback about avoiding magic strings. The constant names follow proper naming conventions.

iOSExtensions/ShareExtension/AppContainerExtension/ShareViewController.cs (3)

1-12: LGTM! Using statements and constants properly defined.

The addition of the UniformTypeIdentifiers using statement and extraction of hardcoded values to constants addresses previous feedback. The constant names follow proper conventions and improve maintainability.


115-147: LGTM! Excellent responder chain traversal and iOS version handling.

The implementation properly:

  • Traverses the responder chain to find UIApplication
  • Handles iOS 18+ with modern API
  • Provides fallback for iOS < 18 using selector
  • Calls CompleteExtension() in both code paths
  • Uses constant for maximum attempts to prevent infinite loops

149-152: LGTM! Clean encapsulation of extension completion.

The method properly encapsulates the extension context completion logic and uses the modern empty array literal syntax.

@hflexgrig
Copy link
Contributor Author

@VladislavAntonyuk only one "issue" remains from code analizers, but it not really an issue!

@VladislavAntonyuk VladislavAntonyuk merged commit 4dba16f into VladislavAntonyuk:main Aug 11, 2025
6 of 8 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Oct 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants