Skip to content

Commit 30ce87b

Browse files
committed
updated android nad ios version + contractServices
1 parent c993cca commit 30ce87b

File tree

14 files changed

+626
-337
lines changed

14 files changed

+626
-337
lines changed

CHANGELOG.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.55.15] - 2025-01-22
9+
10+
### Changed
11+
- **BREAKING**: Updated iOS deployment target to iOS 15.0 to ensure compatibility with iOS 18 SDK requirement
12+
- **BREAKING**: Updated Android target SDK to API level 35 (Android 15) to comply with Google Play requirements
13+
- Updated Android compile SDK to API level 35
14+
- Updated Android Gradle Plugin to version 8.7.3 for better compatibility with API level 35
15+
- Updated iOS deployment target from 8.0 to 15.0 in Xcode project settings
16+
17+
### Added
18+
- Added `joinPoolWithChain` method for joining pools on specific blockchain networks
19+
- Added `leavePoolWithChain` method for leaving pools on specific blockchain networks
20+
- Added comprehensive input validation and error handling for new chain-specific methods
21+
- Added example usage for new chain-specific pool methods in example app
22+
23+
### Technical Details
24+
- **iOS**: Apps using this library will now be compatible with Apple's requirement for iOS 18 SDK (Xcode 16+)
25+
- **Android**: Apps using this library will now be compliant with Google Play's requirement for targeting Android 15 (API level 35)
26+
- The deadline for Android compliance is August 30, 2025
27+
- All existing functionality remains unchanged, only the platform targets have been updated
28+
29+
## [1.55.14] - 2025-01-22 (Android Only Update)
30+
- Updated Android target SDK to API level 35 (Android 15)
31+
- Added `joinPoolWithChain` and `leavePoolWithChain` methods
32+
33+
## [1.55.13] - Previous Release
34+
- Previous functionality and features

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ buildscript {
77
}
88

99
dependencies {
10-
classpath "com.android.tools.build:gradle:8.2.2"
10+
classpath "com.android.tools.build:gradle:8.7.3"
1111
}
1212
}
1313

android/gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Fula_kotlinVersion=1.9.22
22
Fula_minSdkVersion=26
3-
Fula_targetSdkVersion=33
4-
Fula_compileSdkVersion=33
3+
Fula_targetSdkVersion=35
4+
Fula_compileSdkVersion=35
55
Fula_ndkversion=26.2.11394342
66
android.useAndroidX=true
77
android.enableJetifier=true

android/src/main/java/land/fx/fula/FulaModule.java

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,72 @@ public void leavePool(String poolID, Promise promise) {
14031403
});
14041404
}
14051405

1406+
@ReactMethod
1407+
public void joinPoolWithChain(String poolID, String chainName, Promise promise) {
1408+
ThreadUtils.runOnExecutor(() -> {
1409+
Log.d("ReactNative", "joinPoolWithChain: poolID = " + poolID + ", chainName = " + chainName);
1410+
try {
1411+
// Validate inputs
1412+
if (poolID == null || poolID.trim().isEmpty()) {
1413+
promise.reject("INVALID_POOL_ID", "Pool ID cannot be null or empty");
1414+
return;
1415+
}
1416+
if (chainName == null || chainName.trim().isEmpty()) {
1417+
promise.reject("INVALID_CHAIN_NAME", "Chain name cannot be null or empty");
1418+
return;
1419+
}
1420+
if (this.fula == null) {
1421+
promise.reject("FULA_NOT_INITIALIZED", "Fula client is not initialized");
1422+
return;
1423+
}
1424+
1425+
long poolIdLong = Long.parseLong(poolID);
1426+
byte[] result = this.fula.poolJoinWithChain(poolIdLong, chainName);
1427+
String resultString = toString(result);
1428+
promise.resolve(resultString);
1429+
} catch (NumberFormatException e) {
1430+
Log.d("ReactNative", "ERROR: Invalid poolID format: " + e.getMessage());
1431+
promise.reject("INVALID_POOL_ID_FORMAT", "Pool ID must be a valid number: " + poolID, e);
1432+
} catch (Exception e) {
1433+
Log.d("ReactNative", "ERROR:" + e.getMessage());
1434+
promise.reject("JOIN_POOL_WITH_CHAIN_ERROR", "Failed to join pool with chain: " + e.getMessage(), e);
1435+
}
1436+
});
1437+
}
1438+
1439+
@ReactMethod
1440+
public void leavePoolWithChain(String poolID, String chainName, Promise promise) {
1441+
ThreadUtils.runOnExecutor(() -> {
1442+
Log.d("ReactNative", "leavePoolWithChain: poolID = " + poolID + ", chainName = " + chainName);
1443+
try {
1444+
// Validate inputs
1445+
if (poolID == null || poolID.trim().isEmpty()) {
1446+
promise.reject("INVALID_POOL_ID", "Pool ID cannot be null or empty");
1447+
return;
1448+
}
1449+
if (chainName == null || chainName.trim().isEmpty()) {
1450+
promise.reject("INVALID_CHAIN_NAME", "Chain name cannot be null or empty");
1451+
return;
1452+
}
1453+
if (this.fula == null) {
1454+
promise.reject("FULA_NOT_INITIALIZED", "Fula client is not initialized");
1455+
return;
1456+
}
1457+
1458+
long poolIdLong = Long.parseLong(poolID);
1459+
byte[] result = this.fula.poolLeaveWithChain(poolIdLong, chainName);
1460+
String resultString = toString(result);
1461+
promise.resolve(resultString);
1462+
} catch (NumberFormatException e) {
1463+
Log.d("ReactNative", "ERROR: Invalid poolID format: " + e.getMessage());
1464+
promise.reject("INVALID_POOL_ID_FORMAT", "Pool ID must be a valid number: " + poolID, e);
1465+
} catch (Exception e) {
1466+
Log.d("ReactNative", "ERROR:" + e.getMessage());
1467+
promise.reject("LEAVE_POOL_WITH_CHAIN_ERROR", "Failed to leave pool with chain: " + e.getMessage(), e);
1468+
}
1469+
});
1470+
}
1471+
14061472
@ReactMethod
14071473
public void listAvailableReplicationRequests(String poolIDStr, Promise promise) {
14081474
ThreadUtils.runOnExecutor(() -> {
@@ -1930,14 +1996,14 @@ public void streamChunks(String streamID, Promise promise) {
19301996
ThreadUtils.runOnExecutor(() -> {
19311997
try {
19321998
fulamobile.StreamIterator iterator = this.fula.getStreamIterator(streamID);
1933-
1999+
19342000
if (iterator == null) {
19352001
promise.reject("STREAM_ITERATOR_ERROR", "Failed to create StreamIterator");
19362002
return;
19372003
}
19382004

19392005
// Start listening for chunks
1940-
new Handler(Looper.getMainLooper()).post(() ->
2006+
new Handler(Looper.getMainLooper()).post(() ->
19412007
pollIterator(iterator, promise)
19422008
);
19432009
} catch (Exception e) {
@@ -1957,7 +2023,7 @@ private void pollIterator(fulamobile.StreamIterator iterator, Promise promise) {
19572023
emitEvent("onStreamingCompleted", null);
19582024
promise.resolve(null);
19592025
} else {
1960-
new Handler(Looper.getMainLooper()).postDelayed(() ->
2026+
new Handler(Looper.getMainLooper()).postDelayed(() ->
19612027
pollIterator(iterator, promise)
19622028
, 50); // Reduced delay for better responsiveness
19632029
}
@@ -1967,7 +2033,7 @@ private void pollIterator(fulamobile.StreamIterator iterator, Promise promise) {
19672033
promise.resolve(null);
19682034
} else if (e.getMessage() != null && e.getMessage().contains("timeout")) {
19692035
// Retry on timeout
1970-
new Handler(Looper.getMainLooper()).post(() ->
2036+
new Handler(Looper.getMainLooper()).post(() ->
19712037
pollIterator(iterator, promise)
19722038
);
19732039
} else {
@@ -1976,7 +2042,7 @@ private void pollIterator(fulamobile.StreamIterator iterator, Promise promise) {
19762042
}
19772043
}
19782044
}
1979-
2045+
19802046
private void emitEvent(String eventName, String data) {
19812047
try {
19822048
getReactApplicationContext()

example/src/App.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,72 @@ const App = () => {
531531
color={inprogress ? 'green' : 'blue'}
532532
/>
533533
</View>
534+
<View style={styles.section}>
535+
<Button
536+
title={inprogress ? 'Processing...' : 'Join Pool With Chain'}
537+
onPress={async () => {
538+
try {
539+
if (initComplete) {
540+
fula.checkConnection().then((r: any) => {
541+
console.log('connection check');
542+
console.log(r);
543+
if (r) {
544+
console.log('initialization is completed.');
545+
blockchain
546+
.joinPoolWithChain(1, 'mainnet')
547+
.then((res: any) => {
548+
console.log('joined pool with chain successfully');
549+
console.log(res);
550+
})
551+
.catch((e: any) => {
552+
console.log('join pool with chain failed');
553+
console.log(e);
554+
});
555+
}
556+
});
557+
} else {
558+
console.log('wait for init to complete');
559+
}
560+
} catch (e) {
561+
console.log('Error in join pool with chain:', e);
562+
}
563+
}}
564+
color={inprogress ? 'green' : 'blue'}
565+
/>
566+
</View>
567+
<View style={styles.section}>
568+
<Button
569+
title={inprogress ? 'Processing...' : 'Leave Pool With Chain'}
570+
onPress={async () => {
571+
try {
572+
if (initComplete) {
573+
fula.checkConnection().then((r: any) => {
574+
console.log('connection check');
575+
console.log(r);
576+
if (r) {
577+
console.log('initialization is completed.');
578+
blockchain
579+
.leavePoolWithChain(1, 'mainnet')
580+
.then((res: any) => {
581+
console.log('left pool with chain successfully');
582+
console.log(res);
583+
})
584+
.catch((e: any) => {
585+
console.log('leave pool with chain failed');
586+
console.log(e);
587+
});
588+
}
589+
});
590+
} else {
591+
console.log('wait for init to complete');
592+
}
593+
} catch (e) {
594+
console.log('Error in leave pool with chain:', e);
595+
}
596+
}}
597+
color={inprogress ? 'green' : 'blue'}
598+
/>
599+
</View>
534600
<View style={styles.section}>
535601
<Button
536602
title={inprogress ? 'Putting & Getting...' : 'Check Account Balance'}

ios/Fula.mm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,16 @@ @interface RCT_EXTERN_MODULE(FulaModule, NSObject)
154154
withResolver:(RCTPromiseResolveBlock)resolve
155155
withRejecter:(RCTPromiseRejectBlock)reject)
156156

157+
RCT_EXTERN_METHOD(joinPoolWithChain:(NSString *)poolID
158+
withChainName:(NSString *)chainName
159+
withResolver:(RCTPromiseResolveBlock)resolve
160+
withRejecter:(RCTPromiseRejectBlock)reject)
161+
162+
RCT_EXTERN_METHOD(leavePoolWithChain:(NSString *)poolID
163+
withChainName:(NSString *)chainName
164+
withResolver:(RCTPromiseResolveBlock)resolve
165+
withRejecter:(RCTPromiseRejectBlock)reject)
166+
157167

158168
RCT_EXTERN_METHOD(listAvailableReplicationRequests:(NSString *)poolIDStr
159169
withResolver:(RCTPromiseResolveBlock)resolve

ios/Fula.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,80 @@ class FulaModule: NSObject {
14781478
}
14791479
}
14801480

1481+
@objc(joinPoolWithChain:withChainName:withResolver:withRejecter:)
1482+
func joinPoolWithChain(poolID: String, chainName: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1483+
print("ReactNative", "joinPoolWithChain: poolID = ", poolID, ", chainName = ", chainName)
1484+
do {
1485+
// Validate inputs
1486+
guard !poolID.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
1487+
let error = NSError(domain: "FULAErrorDomain", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Pool ID cannot be null or empty"])
1488+
reject("INVALID_POOL_ID", "Pool ID cannot be null or empty", error)
1489+
return
1490+
}
1491+
1492+
guard !chainName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
1493+
let error = NSError(domain: "FULAErrorDomain", code: 1002, userInfo: [NSLocalizedDescriptionKey: "Chain name cannot be null or empty"])
1494+
reject("INVALID_CHAIN_NAME", "Chain name cannot be null or empty", error)
1495+
return
1496+
}
1497+
1498+
guard let fula = self.fula else {
1499+
let error = NSError(domain: "FULAErrorDomain", code: 1003, userInfo: [NSLocalizedDescriptionKey: "Fula client is not initialized"])
1500+
reject("FULA_NOT_INITIALIZED", "Fula client is not initialized", error)
1501+
return
1502+
}
1503+
1504+
guard let poolIdInt = Int(poolID) else {
1505+
let error = NSError(domain: "FULAErrorDomain", code: 1004, userInfo: [NSLocalizedDescriptionKey: "Pool ID must be a valid number: \(poolID)"])
1506+
reject("INVALID_POOL_ID_FORMAT", "Pool ID must be a valid number: \(poolID)", error)
1507+
return
1508+
}
1509+
1510+
let result = try fula.poolJoinWithChain(poolIdInt, chainName: chainName)
1511+
let resultString = String(data: result, encoding: .utf8)
1512+
resolve(resultString)
1513+
} catch let error {
1514+
reject("ERR_FULA", "joinPoolWithChain: \(error.localizedDescription)", error)
1515+
}
1516+
}
1517+
1518+
@objc(leavePoolWithChain:withChainName:withResolver:withRejecter:)
1519+
func leavePoolWithChain(poolID: String, chainName: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
1520+
print("ReactNative", "leavePoolWithChain: poolID = ", poolID, ", chainName = ", chainName)
1521+
do {
1522+
// Validate inputs
1523+
guard !poolID.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
1524+
let error = NSError(domain: "FULAErrorDomain", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Pool ID cannot be null or empty"])
1525+
reject("INVALID_POOL_ID", "Pool ID cannot be null or empty", error)
1526+
return
1527+
}
1528+
1529+
guard !chainName.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
1530+
let error = NSError(domain: "FULAErrorDomain", code: 1002, userInfo: [NSLocalizedDescriptionKey: "Chain name cannot be null or empty"])
1531+
reject("INVALID_CHAIN_NAME", "Chain name cannot be null or empty", error)
1532+
return
1533+
}
1534+
1535+
guard let fula = self.fula else {
1536+
let error = NSError(domain: "FULAErrorDomain", code: 1003, userInfo: [NSLocalizedDescriptionKey: "Fula client is not initialized"])
1537+
reject("FULA_NOT_INITIALIZED", "Fula client is not initialized", error)
1538+
return
1539+
}
1540+
1541+
guard let poolIdInt = Int(poolID) else {
1542+
let error = NSError(domain: "FULAErrorDomain", code: 1004, userInfo: [NSLocalizedDescriptionKey: "Pool ID must be a valid number: \(poolID)"])
1543+
reject("INVALID_POOL_ID_FORMAT", "Pool ID must be a valid number: \(poolID)", error)
1544+
return
1545+
}
1546+
1547+
let result = try fula.poolLeaveWithChain(poolIdInt, chainName: chainName)
1548+
let resultString = String(data: result, encoding: .utf8)
1549+
resolve(resultString)
1550+
} catch let error {
1551+
reject("ERR_FULA", "leavePoolWithChain: \(error.localizedDescription)", error)
1552+
}
1553+
}
1554+
14811555

14821556
@objc(eraseBlData:withRejecter:)
14831557
func eraseBlData(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {

ios/Fula.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
175175
GCC_WARN_UNUSED_FUNCTION = YES;
176176
GCC_WARN_UNUSED_VARIABLE = YES;
177-
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
177+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
178178
MTL_ENABLE_DEBUG_INFO = YES;
179179
ONLY_ACTIVE_ARCH = YES;
180180
SDKROOT = iphoneos;
@@ -218,7 +218,7 @@
218218
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
219219
GCC_WARN_UNUSED_FUNCTION = YES;
220220
GCC_WARN_UNUSED_VARIABLE = YES;
221-
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
221+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
222222
MTL_ENABLE_DEBUG_INFO = NO;
223223
SDKROOT = iphoneos;
224224
VALIDATE_PRODUCT = YES;

0 commit comments

Comments
 (0)