Last active
April 6, 2022 13:17
-
-
Save parthdesai1208/a96f69b23a238c0d5cda8ea08e4f941d to your computer and use it in GitHub Desktop.
Retrofit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object NursingApiClient { | |
lateinit var retrofit: Retrofit | |
val service: ApiInterface by lazy { | |
val builder = Retrofit.Builder() | |
.baseUrl(BASE_URL) //e.g., "https://api.github.com/" | |
//(we can change it at runtime to deal with multiple API versions) | |
//like, Production, staging, developments etc. | |
.addConverterFactory(GsonConverterFactory.create()) | |
val client = OkHttpClient.Builder() | |
client.connectTimeout(60, TimeUnit.SECONDS) | |
client.readTimeout(60, TimeUnit.SECONDS) | |
client.writeTimeout(60, TimeUnit.SECONDS) | |
client.sslSocketFactory(SSLSocketFactory = , X509TrustManager = ) <-- SSL -- | |
//region Interceptor | |
/** | |
* Interceptor will intercept the request before it send to the server | |
* Hereby it will add Authorization and BarerToken in header for security reason | |
* Every time it will generate new random string and new encrypted token | |
* */ | |
val interceptor = Interceptor { | |
var request = it.request() | |
try { | |
val newBuilder = request.newBuilder() | |
val randomStr = randomString(53) | |
val token = Base64.encodeToString( | |
getDeviceBearerToken(randomStr).toByteArray(), | |
Base64.NO_WRAP | |
) | |
//add Authorization in header of the request | |
newBuilder.addHeader("Authorization", randomStr) <-- Key-value pair | |
//add BarerToken in header of the request | |
newBuilder.addHeader("BarerToken", token) | |
//override existing header key-value | |
newBuilder.header("BarerToken", token) | |
//in case you want to pass query in every request | |
newBuilder.url(request.url().newBuilder().addQueryParameter("apikey","your-actual-api-key").build()) | |
request = newBuilder.build() | |
} catch (e: Exception) { | |
} | |
val response = it.proceed(request) | |
response | |
} | |
client.addInterceptor(interceptor) | |
//endregion of interceptor code | |
if (BuildConfig.DEBUG) { //debug request/response log | |
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT) | |
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY | |
client.addInterceptor(loggingInterceptor) | |
client.addInterceptor(ChuckerInterceptor.Builder(App.getApplicationContext()).build()) | |
} | |
builder.client(client.build()) | |
retrofit = builder.build() | |
retrofit.create(ApiInterface::class.java) | |
} | |
} | |
----------------------------------------------------------------------------------------------------------------- | |
interface ApiInterface { | |
//all @GET @POST method goes here | |
} | |
----------------------------------------------------------------------------------------------------------------- | |
for header | |
----------------------------------------------------------------------------------------------------------------- | |
fun getDeviceBearerToken(publicKey: String): String { | |
// val publicKey = randomString(53) | |
val firstKey = publicKey.substring(5, 15) | |
val lastKey = publicKey.substring(publicKey.length - 6) | |
val privateKey = firstKey + lastKey | |
// val plainText = "DKisWorkingOnAES" | |
val plainText = "5tf28+!VmhRVsCGX-nF3-D^EwH#G" | |
val cryptLib = CryptLib() | |
val bearerToken = cryptLib.encryptPlainTextWithRandomIV(plainText, privateKey) | |
return bearerToken | |
} | |
----------------------------------------------------------------------------------------------------------------- | |
public class CryptLib { | |
/** | |
* Encryption mode enumeration | |
*/ | |
private enum EncryptMode { | |
ENCRYPT, DECRYPT | |
} | |
// cipher to be used for encryption and decryption | |
private Cipher _cx; | |
// encryption key and initialization vector | |
private byte[] _key, _iv; | |
public CryptLib() throws NoSuchAlgorithmException, NoSuchPaddingException { | |
// initialize the cipher with transformation AES/CBC/PKCS5Padding | |
_cx = Cipher.getInstance("AES/CBC/PKCS5Padding"); | |
_key = new byte[32]; //256 bit key space | |
_iv = new byte[16]; //128 bit IV | |
} | |
/** | |
* | |
* @param inputText Text to be encrypted or decrypted | |
* @param encryptionKey Encryption key to used for encryption / decryption | |
* @param mode specify the mode encryption / decryption | |
* @param initVector Initialization vector | |
* @return encrypted or decrypted bytes based on the mode | |
* @throws UnsupportedEncodingException | |
* @throws InvalidKeyException | |
* @throws InvalidAlgorithmParameterException | |
* @throws IllegalBlockSizeException | |
* @throws BadPaddingException | |
*/ | |
private byte[] encryptDecrypt(String inputText, String encryptionKey, | |
EncryptMode mode, String initVector) throws UnsupportedEncodingException, | |
InvalidKeyException, InvalidAlgorithmParameterException, | |
IllegalBlockSizeException, BadPaddingException { | |
int len = encryptionKey.getBytes("UTF-8").length; // length of the key provided | |
if (encryptionKey.getBytes("UTF-8").length > _key.length) | |
len = _key.length; | |
int ivlength = initVector.getBytes("UTF-8").length; | |
if(initVector.getBytes("UTF-8").length > _iv.length) | |
ivlength = _iv.length; | |
System.arraycopy(encryptionKey.getBytes("UTF-8"), 0, _key, 0, len); | |
System.arraycopy(initVector.getBytes("UTF-8"), 0, _iv, 0, ivlength); | |
SecretKeySpec keySpec = new SecretKeySpec(_key, "AES"); // Create a new SecretKeySpec for the specified key data and algorithm name. | |
IvParameterSpec ivSpec = new IvParameterSpec(_iv); // Create a new IvParameterSpec instance with the bytes from the specified buffer iv used as initialization vector. | |
// encryption | |
if (mode.equals(EncryptMode.ENCRYPT)) { | |
// Potentially insecure random numbers on Android 4.3 and older. Read for more info. | |
// https://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html | |
_cx.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);// Initialize this cipher instance | |
return _cx.doFinal(inputText.getBytes("UTF-8")); // Finish multi-part transformation (encryption) | |
} else { | |
_cx.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);// Initialize this cipher instance | |
byte[] decodedValue = Base64.decode(inputText.getBytes(), Base64.DEFAULT); | |
return _cx.doFinal(decodedValue); // Finish multi-part transformation (decryption) | |
} | |
} | |
/*** | |
* This function computes the SHA256 hash of input string | |
* @param text input text whose SHA256 hash has to be computed | |
* @param length length of the text to be returned | |
* @return returns SHA256 hash of input text | |
* @throws NoSuchAlgorithmException | |
* @throws UnsupportedEncodingException | |
*/ | |
private static String SHA256 (String text, int length) throws NoSuchAlgorithmException, UnsupportedEncodingException { | |
String resultString; | |
MessageDigest md = MessageDigest.getInstance("SHA-256"); | |
md.update(text.getBytes("UTF-8")); | |
byte[] digest = md.digest(); | |
StringBuilder result = new StringBuilder(); | |
for (byte b : digest) { | |
result.append(String.format("%02x", b)); //convert to hex | |
} | |
if(length > result.toString().length()) { | |
resultString = result.toString(); | |
} else { | |
resultString = result.toString().substring(0, length); | |
} | |
return resultString; | |
} | |
public String encryptPlainText(String plainText, String key, String iv) throws Exception { | |
byte[] bytes = encryptDecrypt(plainText, CryptLib.SHA256(key, 32), EncryptMode.ENCRYPT, iv); | |
return Base64.encodeToString(bytes, Base64.DEFAULT); | |
} | |
public String decryptCipherText(String cipherText, String key, String iv) throws Exception { | |
byte[] bytes = encryptDecrypt(cipherText, CryptLib.SHA256(key, 32), EncryptMode.DECRYPT, iv); | |
return new String(bytes); | |
} | |
public String encryptPlainTextWithRandomIV(String plainText, String key) throws Exception { | |
byte[] bytes = encryptDecrypt(generateRandomIV16() + plainText, CryptLib.SHA256(key, 32), EncryptMode.ENCRYPT, generateRandomIV16()); | |
return Base64.encodeToString(bytes, Base64.DEFAULT); | |
} | |
public String decryptCipherTextWithRandomIV(String cipherText, String key) throws Exception { | |
byte[] bytes = encryptDecrypt(cipherText, CryptLib.SHA256(key, 32), EncryptMode.DECRYPT, generateRandomIV16()); | |
String out = new String(bytes); | |
return out.substring(16, out.length()); | |
} | |
/** | |
* Generate IV with 16 bytes | |
* @return | |
*/ | |
public String generateRandomIV16() { | |
SecureRandom ranGen = new SecureRandom(); | |
byte[] aesKey = new byte[16]; | |
ranGen.nextBytes(aesKey); | |
StringBuilder result = new StringBuilder(); | |
for (byte b : aesKey) { | |
result.append(String.format("%02x", b)); //convert to hex | |
} | |
if (16 > result.toString().length()) { | |
return result.toString(); | |
} else { | |
return result.toString().substring(0, 16); | |
} | |
} | |
} | |
----------------------------------------------------------------------------------------------------------------- |
Gson Builder
Gson gson = new GsonBuilder()
.registerTypeAdapter(Id.class, new IdTypeAdapter())
.enableComplexMapKeySerialization()
.serializeNulls()
.setDateFormat(DateFormat.LONG)
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.setPrettyPrinting()
.setVersion(1.0)
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
xml converter
compile 'com.squareup.retrofit2:converter-simplexml:2.5.0'
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.client(new OkHttpClient())
.addConverterFactory(**SimpleXmlConverterFactory**.create())
.build();
tasks.xml
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<task>
<id link="http://url-to-link.com/task-id">1</id>
<title>Retrofit XML Converter Blog Post</title>
<description>Write blog post: XML Converter with Retrofit</description>
<language>de-de</language>
</task>
</rss>
Task
@Root(name = "task")
public class Task {
@Element(name = "id")
private long id;
@Element(name = "title")
private String title;
@Element(name = "description")
private String description;
@Attribute(required = false)
private String link;
public Task() {}
}
Parse JSON which starts with JSON array
val resp = response.body()?.string()
val listType: Type = object : TypeToken<List<YourModelClass?>?>() {}.type
val posts: ArrayList<YourModelClass> = gson.fromJson(resp, listType)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Converters