└── README.md /README.md: -------------------------------------------------------------------------------- 1 | For the latest version of the Mastercard QR SDK, please visit https://developer.mastercard.com/mastercard-merchant-presented-qr/documentation/device-sdks/ 2 | 3 | --- 4 | # MPQRCoreSDK 5 | 6 | This SDK provides parser for parsing Push Payment QR code. 7 | 8 | You can use this SDK to generate Push Payment QR code string also by filling the data and using `PushPaymentData.generatePushPaymentString()`. See documentation for more information. 9 | 10 | _This sdk only deals with actual QR code strings. So you need to use a separate QR scanning SDK to get QR code strings. You can use [MPQRScanSDK][1]_ 11 | 12 | *This SDK is developed in Objective-C and it works with Swift.* 13 | 14 | ### Requirements: 15 | 1. Xcode 9.0+ 16 | 2. iOS 8.0+ 17 | 18 | ### Features: 19 | 1. Capabilities to parse and validate Push Payment QR code string. 20 | 2. Generate Push Payment QR code string. 21 | 22 | ### Documentation 23 | The code documentation can be found on Github link [here][3]. 24 | 25 | ### Installation 26 | 27 | #### Cocoapods 28 | - In your *Podfile* write the following 29 | 30 | ``` 31 | use_frameworks! 32 | pod 'MPQRCoreSDK' 33 | ``` 34 | 35 | - Do `pod install` 36 | - Everything is setup now 37 | 38 | #### Manual 39 | ##### Swift 40 | - Download the latest release of [MPQRCoreSDK][2]. 41 | - Unzip the file. 42 | - Go to your Xcode project’s target “General” settings. Drag MPQRCoreSDK.framework to the “Embedded Binaries” section. Make sure to select **Copy items if needed** and click Finish. 43 | - Create a new **Run Script Phase** in your app’s target’s **Build Phases** and paste the following snippet in the script text field: 44 | 45 | `bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/MPQRCoreSDK.framework/strip-frameworks.sh"` 46 | 47 | This step is required to work around an App Store submission bug when archiving universal binaries. 48 | 49 | 50 | ##### Objective-C 51 | - Follow same instructions as Swift 52 | 53 | [1]: https://www.github.com/Mastercard/s-qr-scan-sdk-ios 54 | [2]: https://www.github.com/Mastercard/masterpass-qr-core-sdk-ios/releases/download/2.0.7/MPQRCoreCdk-framework-ios.zip 55 | [3]: https://mastercard.github.io/masterpass-qr-core-sdk-ios // Need to have New URL, as this has masterpass word 56 | 57 | ### Usage 58 | 59 | #### Parsing 60 | 61 | __Swift__ 62 | 63 | ```swift 64 | import MPQRCoreSDK 65 | 66 | func parseQRCode(code: String) { 67 | do { 68 | // Parse qr code 69 | let pushData = try MPQRParser.parse(string:code) 70 | // Print data in string format 71 | print(pushData.dumpData()) 72 | } catch let error as MPQRError{ 73 | if let str = error.getString(){ 74 | print("Error: \(str)") 75 | }else 76 | { 77 | print("Unknown error occurred \(error)") 78 | } 79 | } catch { 80 | print("Unknown error occurred \(error)") 81 | } 82 | } 83 | ``` 84 | 85 | __Objective-C__ 86 | 87 | ```objc 88 | @import MPQRCoreSDK; 89 | 90 | - (void)parseQRCode:(NSString *)code { 91 | PushPaymentData *pushPaymentData; 92 | NSString* (^handleError)(MPQRError *) = ^NSString* (MPQRError* error) { 93 | if (error.domain == MPQRErrorDomain) { 94 | return [NSString stringWithFormat:@"Error: %@", [error getString]]; 95 | } 96 | return [NSString stringWithFormat:@"Unkown error occured %@", error]; 97 | }; 98 | 99 | MPQRError *error; 100 | pushPaymentData = [MPQRParser parse:code error:&error]; 101 | 102 | if (error) { 103 | NSLog(handleError(error)); 104 | }else 105 | { 106 | NSLog([pushPaymentData dumpData]); 107 | } 108 | } 109 | ``` 110 | 111 | #### Generating 112 | 113 | __Swift__ 114 | 115 | ```swift 116 | import CoreImage 117 | 118 | func generateQRCode(from string: String) -> UIImage? { 119 | let data = string.data(using: String.Encoding.utf8) 120 | 121 | if let filter = CIFilter(name: "CIQRCodeGenerator") { 122 | filter.setValue(data, forKey: "inputMessage") 123 | // Set scale according to your device display. If the qr code is blurry then increase scale 124 | let transform = CGAffineTransform(scaleX: 3, y: 3) 125 | 126 | if let output = filter.outputImage?.transformed(by: transform) { 127 | return UIImage(ciImage: output) 128 | } 129 | } 130 | return nil 131 | } 132 | 133 | func generatePushPaymentQR() { 134 | // Generate 135 | let pushPaymentData = PushPaymentData() 136 | 137 | // Set required properties on push payment data e.g pushPaymentData.payloadFormatIndicator = "01" 138 | 139 | // Payload format indicator 140 | pushPaymentData.payloadFormatIndicator = "01" 141 | 142 | // Point of initiation method 143 | pushPaymentData.pointOfInitiationMethod = "12" 144 | 145 | // Merchant identifier Visa with tag `02` 146 | pushPaymentData.merchantIdentifierVisa02 = "4600678934521435" 147 | 148 | // Merchant identifier Visa with tag `03` 149 | pushPaymentData.merchantIdentifierVisa03 = "4600678934521467" 150 | 151 | // Merchant identifier MasterCard with tag `04` 152 | pushPaymentData.merchantIdentifierMastercard04 = "555544443333111" 153 | 154 | // Merchant identifier MasterCard with tag `05` 155 | pushPaymentData.merchantIdentifierMastercard05 = "555544443333222" 156 | 157 | // Merchant identifier NPCI with tag `06` 158 | pushPaymentData.merchantIdentifierNPCI06 = "5600678934521435" 159 | 160 | // Merchant identifier NPCI with tag `07` 161 | pushPaymentData.merchantIdentifierNPCI07 = "5600678934521459" 162 | 163 | //Merchant identifier (EMVCo)IFSCCode 164 | pushPaymentData.merchantIdentifierIFSCCODE08 = "6800678934521565" 165 | 166 | //Merchant identifier (Discover) 167 | pushPaymentData.merchantIdentifierDISCOVER09 = "7800678934521675" 168 | 169 | //Merchant identifier (Discover) 170 | pushPaymentData.merchantIdentifierDISCOVER10 = "7900678934521655" 171 | 172 | //Merchant identifier (Amex) 173 | pushPaymentData.merchantIdentifierAMEX11 = "3200678934521434" 174 | 175 | //Merchant identifier (Amex) 176 | pushPaymentData.merchantIdentifierAMEX12 = "3400678934521469" 177 | 178 | //Merchant identifier (JCB) 179 | pushPaymentData.merchantIdentifierJCB13 = "5700678934521457" 180 | 181 | //Merchant identifier (JCB) 182 | pushPaymentData.merchantIdentifierJCB14 = "5800678934521435" 183 | 184 | //Merchant identifier (UnionPay) 185 | pushPaymentData.merchantIdentifierUNIONPAY15 = "5800678934524535" 186 | 187 | //Merchant identifier (UnionPay) 188 | pushPaymentData.merchantIdentifierUNIONPAY16 = "4850678934521598" 189 | 190 | //17 - 25 for merchant identifier EMVCO 191 | try! pushPaymentData.setMerchantIdentifierEMVCODataForTagString("17", data: "4657678934521449") 192 | 193 | 194 | //Merchant Identifier data 26-51 195 | let maiData = MAIData() 196 | var rootTag = "26" 197 | maiData.setRootTag(rootTag) 198 | maiData.AID = "AID0349509H" 199 | try! maiData.setPaymentNetworkSpecific("PNS93484jf", forTag:"01") 200 | try! maiData.setDynamicPaymentNetworkSpecific("PNSDyn8494738") 201 | var str01 = try!maiData.getPaymentNetworkSpecific(forTag: "01") 202 | var arr = maiData.getAllDynamicPaymentNetworkSpecificTags()! 203 | print("testSamplePushPaymentData = \(str01) \(arr)") 204 | try! pushPaymentData.setMAIDataForTagString(rootTag, data: maiData) 205 | 206 | // Merchant category code 207 | pushPaymentData.merchantCategoryCode = "1434" 208 | 209 | // Transaction currency code 210 | pushPaymentData.transactionCurrencyCode = "156" 211 | 212 | // Transaction amount 213 | pushPaymentData.transactionAmount = "83.80" 214 | 215 | let tipType = TipConvenienceIndicator.percentageConvenienceFee 216 | switch tipType { 217 | case .promptedToEnterTip: 218 | // Tip or convenience indicator 219 | pushPaymentData.tipOrConvenienceIndicator = "01" 220 | case .flatConvenienceFee: 221 | // Tip or convenience indicator 222 | pushPaymentData.tipOrConvenienceIndicator = "02" 223 | // Value of convenience fee fixed 224 | pushPaymentData.valueOfConvenienceFeeFixed = "10" 225 | case .percentageConvenienceFee: 226 | // Tip or convenience indicator 227 | pushPaymentData.tipOrConvenienceIndicator = "03" 228 | // Value of convenience fee percentage 229 | pushPaymentData.valueOfConvenienceFeePercentage = "5" 230 | case .unknownTipConvenienceIndicator: 231 | print("do nothing") 232 | } 233 | 234 | // Country code 235 | pushPaymentData.countryCode = "CN" 236 | 237 | // Merchant name 238 | pushPaymentData.merchantName = "BEST TRANSPORT" 239 | 240 | // Merchant city 241 | pushPaymentData.merchantCity = "BEIJING" 242 | 243 | // Postal code 244 | pushPaymentData.postalCode = "56748" 245 | 246 | 247 | // Additional data 248 | let addData = AdditionalData() 249 | addData.storeId = "A6008" 250 | addData.loyaltyNumber = "***" 251 | addData.terminalId = "A6008667" 252 | addData.additionalConsumerDataRequest = "ME" 253 | 254 | var rootSubTag = "50" 255 | var additionalUnrestrictedData = UnrestrictedData() 256 | additionalUnrestrictedData.setRootTag(rootSubTag) 257 | additionalUnrestrictedData.AID = "GUI123" 258 | try! additionalUnrestrictedData.setContextSpecific("CONT", forTag: "01") 259 | try! additionalUnrestrictedData.setDynamicContextSpecific("DYN6") 260 | str01 = try!additionalUnrestrictedData.getContextSpecificData(forTag: "01") 261 | arr = additionalUnrestrictedData.getAllDynamicContextSpecificDataTags()! 262 | try! addData.setUnreserved(additionalUnrestrictedData, forTag: rootSubTag) 263 | 264 | rootSubTag = "51" 265 | additionalUnrestrictedData = UnrestrictedData() 266 | additionalUnrestrictedData.AID = "GUI2" 267 | try! additionalUnrestrictedData.setContextSpecific("CON", forTag: "01") 268 | try! additionalUnrestrictedData.setDynamicContextSpecific("DYN22") 269 | str01 = try!additionalUnrestrictedData.getContextSpecificData(forTag: "01") 270 | arr = additionalUnrestrictedData.getAllDynamicContextSpecificDataTags()! 271 | try! addData.setDynamicTag(additionalUnrestrictedData) 272 | 273 | pushPaymentData.additionalData = addData 274 | 275 | // CRC 276 | pushPaymentData.crc = "6403" 277 | 278 | // Language Data 279 | let langData = LanguageData() 280 | langData.languagePreference = "ZH" 281 | langData.alternateMerchantCity = "北京" 282 | langData.alternateMerchantName = "最佳运输" 283 | pushPaymentData.languageData = langData 284 | 285 | //unrestricted data 286 | rootTag = "88" 287 | let unrestrictedData = UnrestrictedData() 288 | unrestrictedData.setRootTag(rootTag) 289 | unrestrictedData.AID = "GUI12319494" 290 | try! unrestrictedData.setContextSpecific("CONT7586F", forTag: "01") 291 | try! unrestrictedData.setDynamicContextSpecific("DYN647382") 292 | str01 = try!unrestrictedData.getContextSpecificData(forTag: "01") 293 | arr = unrestrictedData.getAllDynamicContextSpecificDataTags()! 294 | try! pushPaymentData.setUnreservedDataForTagString(rootTag, data: unrestrictedData) 295 | 296 | var ppdString:String? 297 | do { 298 | // Validate generated data 299 | ppdString = try pushPaymentData.generatePushPaymentString() 300 | } catch { 301 | print("Error occurred during validation \(error)") 302 | return 303 | } 304 | 305 | // Generate image 306 | let image = generateQRCode(from: ppdString!) 307 | } 308 | ``` 309 | 310 | __Objective-C__ 311 | 312 | ```objc 313 | @import CoreImage; 314 | 315 | - (UIImage *)generateQRCode:(NSString *)string { 316 | NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding]; 317 | CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; 318 | if (!filter || !data) 319 | return nil; 320 | 321 | [filter setValue:data forKey:@"inputMessage"]; 322 | CGAffineTransform transform = CGAffineTransformMakeScale(3, 3); 323 | CIImage *image = [[filter outputImage] imageByApplyingTransform:transform]; 324 | return [UIImage imageWithCIImage:image]; 325 | } 326 | 327 | - (void)generatePushPaymentQR { 328 | // Generate 329 | PushPaymentData *pushPaymentData = [[PushPaymentData alloc] init]; 330 | 331 | // Set required properties on push payment data e.g pushPaymentData.payloadFormatIndicator = @"01" 332 | 333 | // Payload format indicator 334 | pushPaymentData.payloadFormatIndicator = @"01"; 335 | 336 | // Point of initiation method 337 | pushPaymentData.pointOfInitiationMethod = @"12"; 338 | 339 | // Merchant identifier Visa with tag `02` 340 | pushPaymentData.merchantIdentifierVisa02 = @"4600678934521435"; 341 | 342 | // Merchant identifier Visa with tag `03` 343 | pushPaymentData.merchantIdentifierVisa03 = @"4600678934521467"; 344 | 345 | // Merchant identifier MasterCard with tag `04` 346 | pushPaymentData.merchantIdentifierMastercard04 = @"555544443333111"; 347 | 348 | // Merchant identifier MasterCard with tag `05` 349 | pushPaymentData.merchantIdentifierMastercard05 = @"555544443333222"; 350 | 351 | // Merchant identifier NPCI with tag `06` 352 | pushPaymentData.merchantIdentifierNPCI06 = @"5600678934521435"; 353 | 354 | // Merchant identifier NPCI with tag `07` 355 | pushPaymentData.merchantIdentifierNPCI07 = @"5600678934521459"; 356 | 357 | //Merchant identifier (EMVCo)IFSCCode 358 | pushPaymentData.merchantIdentifierIFSCCODE08 = @"6800678934521565"; 359 | 360 | //Merchant identifier (Discover) 361 | pushPaymentData.merchantIdentifierDISCOVER09 = @"7800678934521675"; 362 | 363 | //Merchant identifier (Discover) 364 | pushPaymentData.merchantIdentifierDISCOVER10 = @"7900678934521655"; 365 | 366 | //Merchant identifier (Amex) 367 | pushPaymentData.merchantIdentifierAMEX11 = @"3200678934521434"; 368 | 369 | //Merchant identifier (Amex) 370 | pushPaymentData.merchantIdentifierAMEX12 = @"3400678934521469"; 371 | 372 | //Merchant identifier (JCB) 373 | pushPaymentData.merchantIdentifierJCB13 = @"5700678934521457"; 374 | 375 | //Merchant identifier (JCB) 376 | pushPaymentData.merchantIdentifierJCB14 = @"5800678934521435"; 377 | 378 | //Merchant identifier (UnionPay) 379 | pushPaymentData.merchantIdentifierUNIONPAY15 = @"5800678934524535"; 380 | 381 | //Merchant identifier (UnionPay) 382 | pushPaymentData.merchantIdentifierUNIONPAY16 = @"4850678934521598"; 383 | 384 | //17 - 25 for merchant identifier EMVCO 385 | MPQRError* error; 386 | [pushPaymentData setMerchantIdentifierEMVCODataForTagString:@"17" data:@"4657678934521449" error:&error]; 387 | 388 | //Merchant Identifier data 26-51 389 | MAIData* maiData = [MAIData new]; 390 | NSString* rootTag = @"26"; 391 | [maiData setRootTag:rootTag]; 392 | maiData.AID = @"AID0349509H"; 393 | [maiData setPaymentNetworkSpecific:@"PNS93484jf" forTag:@"01" error:&error]; 394 | [maiData setDynamicPaymentNetworkSpecific:@"PNSDyn8494738" error:&error]; 395 | NSString* strValue01 = [maiData getPaymentNetworkSpecificForTag:@"01" error:&error]; 396 | NSArray* arrTags = [maiData getAllDynamicPaymentNetworkSpecificTags]; 397 | [pushPaymentData setMAIDataForTagString:rootTag data:maiData error:&error]; 398 | 399 | // Merchant category code 400 | pushPaymentData.merchantCategoryCode = @"1434"; 401 | 402 | // Transaction currency code 403 | pushPaymentData.transactionCurrencyCode = @"156"; 404 | 405 | // Transaction amount 406 | pushPaymentData.transactionAmount = @"83.80"; 407 | 408 | TipConvenienceIndicator tipType = percentageConvenienceFee; 409 | switch (tipType) { 410 | case promptedToEnterTip: 411 | // Tip or convenience indicator 412 | pushPaymentData.tipOrConvenienceIndicator = @"01"; 413 | break; 414 | case flatConvenienceFee: 415 | // Tip or convenience indicator 416 | pushPaymentData.tipOrConvenienceIndicator = @"02"; 417 | // Value of convenience fee fixed 418 | pushPaymentData.valueOfConvenienceFeeFixed= @"10"; 419 | break; 420 | case percentageConvenienceFee: 421 | // Tip or convenience indicator 422 | pushPaymentData.tipOrConvenienceIndicator = @"03"; 423 | // Value of convenience fee percentage 424 | pushPaymentData.valueOfConvenienceFeePercentage = @"5"; 425 | default: 426 | break; 427 | } 428 | 429 | // Country code 430 | pushPaymentData.countryCode = @"CN"; 431 | 432 | // Merchant name 433 | pushPaymentData.merchantName = @"BEST TRANSPORT"; 434 | 435 | // Merchant city 436 | pushPaymentData.merchantCity = @"BEIJING"; 437 | 438 | // Postal code 439 | pushPaymentData.postalCode = @"56748"; 440 | 441 | // Additional data 442 | AdditionalData* addData = [AdditionalData new]; 443 | addData.storeId = @"A6008"; 444 | addData.loyaltyNumber = @"***"; 445 | addData.terminalId = @"A6008667"; 446 | addData.additionalConsumerDataRequest = @"ME"; 447 | 448 | NSString* rootSubTag = @"50"; 449 | UnrestrictedData* additionalUnrestrictedData = [UnrestrictedData new]; 450 | [additionalUnrestrictedData setRootTag:rootSubTag]; 451 | additionalUnrestrictedData.AID = @"GUI123"; 452 | [additionalUnrestrictedData setContextSpecificData:@"CONT" forTag:@"01" error:&error]; 453 | [additionalUnrestrictedData setDynamicContextSpecificData:@"DYN6" error:&error]; 454 | strValue01 = [additionalUnrestrictedData getContextSpecificDataForTag:@"01" error:&error]; 455 | arrTags = [additionalUnrestrictedData getAllDynamicContextSpecificDataTags]; 456 | [addData setUnreservedData:additionalUnrestrictedData forTag:rootSubTag error:&error]; 457 | 458 | rootSubTag = @"51"; 459 | additionalUnrestrictedData = [UnrestrictedData new]; 460 | additionalUnrestrictedData.AID = @"GUI2"; 461 | [additionalUnrestrictedData setContextSpecificData:@"CON" forTag:@"01" error:&error]; 462 | [additionalUnrestrictedData setDynamicContextSpecificData:@"DYN22" error:&error]; 463 | strValue01 = [additionalUnrestrictedData getContextSpecificDataForTag:@"01" error:&error]; 464 | arrTags = [additionalUnrestrictedData getAllDynamicContextSpecificDataTags]; 465 | [addData setDynamicTag:additionalUnrestrictedData error:&error]; 466 | 467 | pushPaymentData.additionalData = addData; 468 | 469 | // CRC 470 | pushPaymentData.crc = @"6403"; 471 | 472 | // Language Data 473 | LanguageData* langData = [LanguageData new]; 474 | langData.languagePreference = @"ZH"; 475 | langData.alternateMerchantCity = @"北京"; 476 | langData.alternateMerchantName = @"最佳运输"; 477 | pushPaymentData.languageData = langData; 478 | 479 | //unrestricted data 480 | rootTag = @"88"; 481 | UnrestrictedData* unrestrictedData = [UnrestrictedData new]; 482 | [unrestrictedData setRootTag:rootTag]; 483 | unrestrictedData.AID = @"GUI12319494"; 484 | [unrestrictedData setContextSpecificData:@"CONT7586F" forTag:@"01" error:&error]; 485 | [unrestrictedData setDynamicContextSpecificData:@"DYN647382" error:&error]; 486 | strValue01 = [unrestrictedData getContextSpecificDataForTag:@"01" error:&error]; 487 | arrTags = [unrestrictedData getAllDynamicContextSpecificDataTags]; 488 | [pushPaymentData setTagInfoValue:unrestrictedData forTagString:rootTag error:&error]; 489 | 490 | NSString* strQRCode = [pushPaymentData generatePushPaymentString:&error]; 491 | 492 | if (error) { 493 | NSLog(@"Error: %@", error); 494 | } else { 495 | // Generate image 496 | UIImage *image = [self generateQRCode: strQRCode]; 497 | } 498 | } 499 | ``` 500 | 501 | --------------------------------------------------------------------------------