0
# Extension Management
1
2
Extension manager for controlling Mail extensions, reloading content blockers, and managing visible messages. This module provides the core functionality for managing Mail extension lifecycle and operations.
3
4
## Capabilities
5
6
### MEExtensionManager
7
8
Manager for Mail extension operations and reloading. This is the primary class for controlling extension behavior and triggering system updates.
9
10
```python { .api }
11
class MEExtensionManager:
12
def reloadContentBlockerWithIdentifier_completionHandler_(
13
self,
14
identifier: str, # Content blocker identifier
15
completionHandler # Completion handler: (NSError or None) -> None
16
):
17
"""
18
Reload a content blocker with the specified identifier.
19
20
Args:
21
identifier: The unique identifier of the content blocker to reload
22
completionHandler: Completion handler called when reload completes,
23
receives an NSError if the operation failed, None on success
24
"""
25
26
def reloadVisibleMessagesWithCompletionHandler_(
27
self,
28
completionHandler # Completion handler: (NSError or None) -> None
29
):
30
"""
31
Reload all visible messages in the Mail application.
32
33
Args:
34
completionHandler: Completion handler called when reload completes,
35
receives an NSError if the operation failed, None on success
36
"""
37
```
38
39
### MEExtensionViewController
40
41
Base view controller class for Mail extensions. Provides the foundation for creating custom view controllers in Mail extensions.
42
43
```python { .api }
44
class MEExtensionViewController:
45
"""
46
Base view controller for Mail extensions.
47
48
This class provides the foundation for creating custom view controllers
49
that integrate with the Mail application interface.
50
51
Note: This class cannot be instantiated directly using init() or new().
52
Subclass this class to create custom extension view controllers.
53
"""
54
```
55
56
## Usage Examples
57
58
### Reloading Content Blockers
59
60
```python
61
import MailKit
62
63
# Reload a specific content blocker
64
def reload_content_blocker(extension_manager, blocker_id):
65
"""Reload a content blocker and handle the result."""
66
67
def completion_handler(error):
68
if error is None:
69
print(f"Successfully reloaded content blocker: {blocker_id}")
70
else:
71
print(f"Failed to reload content blocker {blocker_id}: {error}")
72
73
extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
74
identifier=blocker_id,
75
completionHandler=completion_handler
76
)
77
78
# Example usage
79
# extension_manager would be provided by the Mail framework
80
# reload_content_blocker(extension_manager, "com.example.mailblocker")
81
```
82
83
### Reloading Visible Messages
84
85
```python
86
import MailKit
87
88
# Reload all visible messages
89
def reload_visible_messages(extension_manager):
90
"""Reload all visible messages and handle the result."""
91
92
def completion_handler(error):
93
if error is None:
94
print("Successfully reloaded visible messages")
95
else:
96
print(f"Failed to reload visible messages: {error}")
97
98
extension_manager.reloadVisibleMessagesWithCompletionHandler_(
99
completionHandler=completion_handler
100
)
101
102
# Example usage
103
# extension_manager would be provided by the Mail framework
104
# reload_visible_messages(extension_manager)
105
```
106
107
### Extension Manager Utility Class
108
109
```python
110
import MailKit
111
112
class MailExtensionManager:
113
"""Utility class for managing Mail extension operations."""
114
115
def __init__(self, extension_manager):
116
"""
117
Initialize with a MEExtensionManager instance.
118
119
Args:
120
extension_manager: MEExtensionManager instance from the Mail framework
121
"""
122
self.extension_manager = extension_manager
123
self.reload_callbacks = {}
124
125
def reload_content_blocker_async(self, blocker_id, callback=None):
126
"""
127
Asynchronously reload a content blocker.
128
129
Args:
130
blocker_id: Identifier of the content blocker
131
callback: Optional callback function to call on completion
132
"""
133
def completion_handler(error):
134
success = error is None
135
if callback:
136
callback(blocker_id, success, error)
137
138
# Store result for later retrieval
139
self.reload_callbacks[blocker_id] = {
140
"success": success,
141
"error": error,
142
"timestamp": __import__("time").time()
143
}
144
145
self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
146
identifier=blocker_id,
147
completionHandler=completion_handler
148
)
149
150
def reload_visible_messages_async(self, callback=None):
151
"""
152
Asynchronously reload visible messages.
153
154
Args:
155
callback: Optional callback function to call on completion
156
"""
157
def completion_handler(error):
158
success = error is None
159
if callback:
160
callback(success, error)
161
162
self.extension_manager.reloadVisibleMessagesWithCompletionHandler_(
163
completionHandler=completion_handler
164
)
165
166
def get_last_reload_result(self, blocker_id):
167
"""
168
Get the result of the last reload operation for a content blocker.
169
170
Args:
171
blocker_id: Identifier of the content blocker
172
173
Returns:
174
dict: Result information or None if no reload has been performed
175
"""
176
return self.reload_callbacks.get(blocker_id)
177
178
# Example usage
179
# manager = MailExtensionManager(extension_manager_instance)
180
#
181
# def reload_callback(blocker_id, success, error):
182
# if success:
183
# print(f"Content blocker {blocker_id} reloaded successfully")
184
# else:
185
# print(f"Failed to reload content blocker {blocker_id}: {error}")
186
#
187
# manager.reload_content_blocker_async("com.example.blocker", reload_callback)
188
```
189
190
### Batch Content Blocker Operations
191
192
```python
193
import MailKit
194
195
class BatchExtensionManager:
196
"""Manager for batch extension operations."""
197
198
def __init__(self, extension_manager):
199
self.extension_manager = extension_manager
200
self.pending_operations = {}
201
202
def reload_multiple_content_blockers(self, blocker_ids, completion_callback=None):
203
"""
204
Reload multiple content blockers and track completion.
205
206
Args:
207
blocker_ids: List of content blocker identifiers
208
completion_callback: Called when all operations complete
209
"""
210
batch_id = f"batch_{__import__('time').time()}"
211
self.pending_operations[batch_id] = {
212
"total": len(blocker_ids),
213
"completed": 0,
214
"results": {},
215
"callback": completion_callback
216
}
217
218
def individual_completion(blocker_id, error):
219
batch_info = self.pending_operations[batch_id]
220
batch_info["completed"] += 1
221
batch_info["results"][blocker_id] = {
222
"success": error is None,
223
"error": error
224
}
225
226
# Check if batch is complete
227
if batch_info["completed"] == batch_info["total"]:
228
if batch_info["callback"]:
229
batch_info["callback"](batch_id, batch_info["results"])
230
# Clean up
231
del self.pending_operations[batch_id]
232
233
# Start all reload operations
234
for blocker_id in blocker_ids:
235
self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
236
identifier=blocker_id,
237
completionHandler=lambda error, bid=blocker_id: individual_completion(bid, error)
238
)
239
240
return batch_id
241
242
def get_batch_status(self, batch_id):
243
"""
244
Get the status of a batch operation.
245
246
Args:
247
batch_id: Batch operation identifier
248
249
Returns:
250
dict: Batch status information or None if not found
251
"""
252
return self.pending_operations.get(batch_id)
253
254
# Example usage
255
# batch_manager = BatchExtensionManager(extension_manager_instance)
256
#
257
# def batch_completion(batch_id, results):
258
# print(f"Batch {batch_id} completed:")
259
# for blocker_id, result in results.items():
260
# status = "SUCCESS" if result["success"] else "FAILED"
261
# print(f" {blocker_id}: {status}")
262
#
263
# blocker_list = ["com.example.blocker1", "com.example.blocker2", "com.example.blocker3"]
264
# batch_id = batch_manager.reload_multiple_content_blockers(blocker_list, batch_completion)
265
```
266
267
### Error Handling and Retry Logic
268
269
```python
270
import MailKit
271
import time
272
273
class RobustExtensionManager:
274
"""Extension manager with retry logic and error handling."""
275
276
def __init__(self, extension_manager, max_retries=3, retry_delay=1.0):
277
self.extension_manager = extension_manager
278
self.max_retries = max_retries
279
self.retry_delay = retry_delay
280
self.retry_attempts = {}
281
282
def reload_content_blocker_with_retry(self, blocker_id, final_callback=None):
283
"""
284
Reload content blocker with automatic retry on failure.
285
286
Args:
287
blocker_id: Content blocker identifier
288
final_callback: Callback called after all retries exhausted
289
"""
290
attempt_key = f"{blocker_id}_{time.time()}"
291
self.retry_attempts[attempt_key] = 0
292
293
def attempt_reload():
294
attempt_count = self.retry_attempts[attempt_key]
295
296
def completion_handler(error):
297
if error is None:
298
# Success - clean up and notify
299
if attempt_key in self.retry_attempts:
300
del self.retry_attempts[attempt_key]
301
if final_callback:
302
final_callback(blocker_id, True, None, attempt_count + 1)
303
else:
304
# Failure - check if we should retry
305
self.retry_attempts[attempt_key] += 1
306
current_attempt = self.retry_attempts[attempt_key]
307
308
if current_attempt < self.max_retries:
309
print(f"Retrying content blocker reload {blocker_id} (attempt {current_attempt + 1}/{self.max_retries})")
310
# Schedule retry after delay
311
__import__("threading").Timer(self.retry_delay, attempt_reload).start()
312
else:
313
# All retries exhausted
314
if attempt_key in self.retry_attempts:
315
del self.retry_attempts[attempt_key]
316
if final_callback:
317
final_callback(blocker_id, False, error, current_attempt)
318
319
self.extension_manager.reloadContentBlockerWithIdentifier_completionHandler_(
320
identifier=blocker_id,
321
completionHandler=completion_handler
322
)
323
324
# Start first attempt
325
attempt_reload()
326
327
# Example usage
328
# robust_manager = RobustExtensionManager(extension_manager_instance, max_retries=3, retry_delay=2.0)
329
#
330
# def final_callback(blocker_id, success, error, attempts):
331
# if success:
332
# print(f"Content blocker {blocker_id} reloaded successfully after {attempts} attempts")
333
# else:
334
# print(f"Failed to reload content blocker {blocker_id} after {attempts} attempts: {error}")
335
#
336
# robust_manager.reload_content_blocker_with_retry("com.example.blocker", final_callback)
337
```