|
| 1 | +# Ti.Android.Share |
| 2 | + |
| 3 | +A native Android module for Titanium SDK that provides seamless image and text sharing using Android's FileProvider API. |
| 4 | + |
| 5 | +    |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +This module solves a critical limitation in Titanium SDK when sharing images on Android 7.0+ (API 24+). Modern Android versions require the use of `content://` URIs through FileProvider instead of `file://` URIs for security reasons. While Titanium SDK provides intent-based sharing capabilities, it lacks native FileProvider support, making image sharing problematic with apps like WhatsApp, Telegram, and email clients. |
| 10 | + |
| 11 | +`ti.android.share` bridges this gap by providing a simple JavaScript API that handles all the complexity of FileProvider configuration, URI generation, and secure file sharing. |
| 12 | + |
| 13 | +## Features |
| 14 | + |
| 15 | +- Share images from Resources, Blobs, or file paths |
| 16 | +- Automatic FileProvider URI generation |
| 17 | +- Support for text and image combination sharing |
| 18 | +- Optional callback to handle share results (success, cancelled, or error) |
| 19 | +- Works with WhatsApp, Telegram, Email, and all Android share targets |
| 20 | +- Compatible with Titanium SDK 13.x and modern Android versions |
| 21 | + |
| 22 | +## Requirements |
| 23 | + |
| 24 | +- Titanium SDK 13.0.0 or higher |
| 25 | +- Android target SDK 24 or higher |
| 26 | + |
| 27 | +## Installation |
| 28 | + |
| 29 | +### Download the module |
| 30 | + |
| 31 | +Download the latest release from the [releases page](https://github.com/deckameron/Ti.Android.Share/releases) or build from source. |
| 32 | + |
| 33 | +### Add to your project |
| 34 | + |
| 35 | +1. Copy the module ZIP file to your project root directory |
| 36 | +2. Add the module to your `tiapp.xml`: |
| 37 | + |
| 38 | +```xml |
| 39 | +<modules> |
| 40 | + <module platform="android">ti.android.share</module> |
| 41 | +</modules> |
| 42 | +``` |
| 43 | + |
| 44 | +### FileProvider configuration |
| 45 | + |
| 46 | +The module automatically configures the FileProvider, but ensure your `tiapp.xml` has a valid application ID: |
| 47 | + |
| 48 | +```xml |
| 49 | +<id>com.yourcompany.yourapp</id> |
| 50 | +``` |
| 51 | + |
| 52 | +The module will use `com.yourcompany.yourapp.fileprovider` as the FileProvider authority. |
| 53 | + |
| 54 | +## Usage |
| 55 | + |
| 56 | +### Basic example |
| 57 | + |
| 58 | +```javascript |
| 59 | +const ShareModule = require('ti.android.share'); |
| 60 | + |
| 61 | +ShareModule.share({ |
| 62 | + message: "Check out this amazing content!", |
| 63 | + subject: "Sharing from my app", |
| 64 | + image: "/images/photo.jpg" |
| 65 | +}); |
| 66 | +``` |
| 67 | + |
| 68 | +### Share image from Resources |
| 69 | + |
| 70 | +```javascript |
| 71 | +ShareModule.share({ |
| 72 | + message: "Look at this picture!", |
| 73 | + image: "/images/my-image.png" |
| 74 | +}); |
| 75 | +``` |
| 76 | + |
| 77 | +### Share image from Blob |
| 78 | + |
| 79 | +```javascript |
| 80 | +const imageView = Ti.UI.createImageView({ |
| 81 | + image: 'https://example.com/image.jpg' |
| 82 | +}); |
| 83 | + |
| 84 | +// After image loads |
| 85 | +imageView.addEventListener('load', function() { |
| 86 | + ShareModule.share({ |
| 87 | + message: "Sharing dynamically loaded image", |
| 88 | + image: imageView.toBlob() |
| 89 | + }); |
| 90 | +}); |
| 91 | +``` |
| 92 | + |
| 93 | +### Share text only |
| 94 | + |
| 95 | +```javascript |
| 96 | +ShareModule.share({ |
| 97 | + message: "Just sharing some text", |
| 98 | + subject: "Important message" |
| 99 | +}); |
| 100 | +``` |
| 101 | + |
| 102 | +### Share with callback |
| 103 | + |
| 104 | +```javascript |
| 105 | +ShareModule.share({ |
| 106 | + message: "Check this out!", |
| 107 | + image: "/images/photo.jpg", |
| 108 | + subject: "Amazing content", |
| 109 | + callback: function(e) { |
| 110 | + if (e.success) { |
| 111 | + Ti.API.info("Share completed: " + e.message); |
| 112 | + // Handle success - maybe track analytics |
| 113 | + } else { |
| 114 | + Ti.API.error("Share failed: " + e.message); |
| 115 | + // Handle cancellation or error |
| 116 | + } |
| 117 | + } |
| 118 | +}); |
| 119 | +``` |
| 120 | + |
| 121 | +## API Reference |
| 122 | + |
| 123 | +### Methods |
| 124 | + |
| 125 | +#### `share(options)` |
| 126 | + |
| 127 | +Opens the Android share dialog with the specified content. |
| 128 | + |
| 129 | +**Parameters:** |
| 130 | + |
| 131 | +- `options` (Object): Configuration object with the following properties: |
| 132 | + - `message` (String, optional): Text content to share |
| 133 | + - `subject` (String, optional): Subject line for sharing (used by email apps) |
| 134 | + - `image` (String|TiBlob, optional): Image to share. Can be: |
| 135 | + - Path to resource file (e.g., `/images/photo.jpg`) |
| 136 | + - Path from applicationDataDirectory |
| 137 | + - TiBlob object (from `imageView.toBlob()`, camera, etc.) |
| 138 | + - `callback` (Function, optional): Callback function to receive share result |
| 139 | + |
| 140 | +**Callback object properties:** |
| 141 | + |
| 142 | +- `success` (Boolean): `true` if share completed successfully, `false` if cancelled or failed |
| 143 | +- `message` (String): Descriptive message about the share result: |
| 144 | + - `"Share completed successfully"` - User completed the share action |
| 145 | + - `"Share cancelled by user"` - User cancelled the share dialog |
| 146 | + - `"Error: [description]"` - An error occurred during sharing |
| 147 | + |
| 148 | +**Returns:** void |
| 149 | + |
| 150 | +**Example:** |
| 151 | + |
| 152 | +```javascript |
| 153 | +ShareModule.share({ |
| 154 | + message: "Hello World", |
| 155 | + subject: "Greeting", |
| 156 | + image: myImageBlob, |
| 157 | + callback: function(e) { |
| 158 | + console.log("Success: " + e.success); |
| 159 | + console.log("Message: " + e.message); |
| 160 | + } |
| 161 | +}); |
| 162 | +``` |
| 163 | + |
| 164 | +## How it works |
| 165 | + |
| 166 | +The module handles the following automatically: |
| 167 | + |
| 168 | +1. **Resource location**: Attempts to find images in multiple locations: |
| 169 | + - Application resources (`/app/_app_/Resources/`) |
| 170 | + - Android assets |
| 171 | + - Application data directory |
| 172 | + - Cache directory |
| 173 | + |
| 174 | +2. **File preparation**: For resource files and Blobs: |
| 175 | + - Copies the file to the cache directory |
| 176 | + - Ensures the file is accessible by the FileProvider |
| 177 | + |
| 178 | +3. **URI generation**: Creates a secure `content://` URI using Android's FileProvider |
| 179 | + |
| 180 | +4. **Permission granting**: Adds `FLAG_GRANT_READ_URI_PERMISSION` so receiving apps can access the file |
| 181 | + |
| 182 | +5. **Intent creation**: Builds a proper `ACTION_SEND` intent with all necessary flags |
| 183 | + |
| 184 | +6. **Result handling**: When a callback is provided, uses `startActivityForResult` to capture the share outcome and notify your application |
| 185 | + |
| 186 | +## Troubleshooting |
| 187 | + |
| 188 | +### Callback not firing |
| 189 | + |
| 190 | +The callback relies on Android's activity result system. Note that: |
| 191 | + |
| 192 | +- `success: true` means the user selected an app and the share intent was delivered |
| 193 | +- `success: false` means the user cancelled the share dialog or an error occurred |
| 194 | +- Some apps may not properly report back to the activity result system |
| 195 | +- The callback indicates the share was initiated, not necessarily that the recipient app completed the action |
| 196 | + |
| 197 | +### Image not found error |
| 198 | + |
| 199 | +If you see logs indicating the image wasn't found, verify: |
| 200 | + |
| 201 | +- The image path is correct (use `/images/photo.jpg`, not `images/photo.jpg`) |
| 202 | +- The image exists in your `Resources` folder or specified directory |
| 203 | +- Check the `adb logcat` output for detailed path information |
| 204 | + |
| 205 | +### WhatsApp/Telegram not showing image |
| 206 | + |
| 207 | +Ensure: |
| 208 | + |
| 209 | +- The image file is a valid JPEG or PNG |
| 210 | +- The file size is reasonable (< 5MB recommended) |
| 211 | +- Your app has necessary permissions in `tiapp.xml`: |
| 212 | + |
| 213 | +```xml |
| 214 | +<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> |
| 215 | +<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> |
| 216 | +``` |
| 217 | + |
| 218 | +## Contributing |
| 219 | + |
| 220 | +Contributions are welcome! Please feel free to submit a Pull Request. |
| 221 | + |
| 222 | +1. Fork the repository |
| 223 | +2. Create your feature branch (`git checkout -b feature/amazing-feature`) |
| 224 | +3. Commit your changes (`git commit -m 'Add some amazing feature'`) |
| 225 | +4. Push to the branch (`git push origin feature/amazing-feature`) |
| 226 | +5. Open a Pull Request |
0 commit comments