<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>nodemtp &amp;mdash; Gerrit Niezen</title>
    <link>https://gerritniezen.com/tag:nodemtp</link>
    <description>Maker of open-source software and hardware.</description>
    <pubDate>Thu, 30 Apr 2026 04:15:11 +0000</pubDate>
    <image>
      <url>https://i.snap.as/aMPXpIot.png</url>
      <title>nodemtp &amp;mdash; Gerrit Niezen</title>
      <link>https://gerritniezen.com/tag:nodemtp</link>
    </image>
    <item>
      <title>Using MTP on macOS with Node.js: Part 5</title>
      <link>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-5?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Feature image&#xA;&#xA;Today I managed to get my new MTP module for Node.js working in Electron. There are still a couple of rough edges to smooth over, but I can retrieve a file from the device and then load and read it using Node&#39;s fs module:&#xA;    &#xA;var list = mtp.getFileListing();&#xA;console.log(&#39;Files:&#39;, list);&#xA;mtp.getFile(.maxBy(list, &#39;id&#39;).id, &#39;test.ibf&#39;);&#xA;fs.readFile(&#39;test.ibf&#39;, (err, data) =  {&#xA;  return cb(err, data);&#xA;});&#xA;&#xA;In this specific instance, there are a bunch of files on the device, and I want to retrieve the one with the highest id, so I use .maxBy() from lodash. mtp.getFile() gets the file from the device and saves it locally. I then use fs.readFile to read the file from the local disk.&#xA;&#xA;Since I&#39;m using version 3 of N-API and it&#39;s only available on Node v10 and higher, I needed to use the latest Electron v3.0.0-beta.4, which has Node v10.2.0 inside. Electron v2 has Node v8 inside, but for v8 N-API is still experimental, and also only supports N-API v1 and v2. Hopefully a stable version of Electron v3 will be released soon, so that I can get this code into the Tidepool Uploader.&#xA;&#xA;nodemtp&#xA;&#xA;iComment on this post/i&#xD;&#xA;div id=&#34;cusdisthread&#34;/div]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://images.unsplash.com/photo-1480694313141-fce5e697ee25?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=16cee079798c8b1aa5098bcb994f7af3" alt="Feature image"/></p>

<p>Today I managed to get my new <a href="https://github.com/tidepool-org/node-mtp">MTP module for Node.js</a> working in Electron. There are still a couple of rough edges to smooth over, but I can retrieve a file from the device and then load and read it using Node&#39;s <code>fs</code> module:</p>

<pre><code class="language-js">var list = mtp.getFileListing();
console.log(&#39;Files:&#39;, list);
mtp.getFile(_.maxBy(list, &#39;id&#39;).id, &#39;test.ibf&#39;);
fs.readFile(&#39;test.ibf&#39;, (err, data) =&gt; {
  return cb(err, data);
});
</code></pre>

<p>In this specific instance, there are a bunch of files on the device, and I want to retrieve the one with the highest <code>id</code>, so I use <code>_.maxBy()</code> from <a href="https://lodash.com/docs/#maxBy">lodash</a>. <code>mtp.getFile()</code> gets the file from the device and saves it locally. I then use <code>fs.readFile</code> to read the file from the local disk.</p>

<p>Since I&#39;m using version 3 of N-API and it&#39;s <a href="https://nodejs.org/api/n-api.html#n_api_n_api_version_matrix">only available</a> on Node v10 and higher, I needed to use the latest Electron <code>v3.0.0-beta.4</code>, which has Node v10.2.0 inside. Electron v2 has Node v8 inside, but for v8 N-API is still experimental, and also only supports N-API v1 and v2. Hopefully a stable version of Electron v3 will be released soon, so that I can get this code into the <a href="https://tidepool.org/uploader">Tidepool Uploader</a>.</p>

<p><a href="https://gerritniezen.com/tag:nodemtp" class="hashtag"><span>#</span><span class="p-category">nodemtp</span></a></p>

<p><i>Comment on this post</i>
<div id="cusdis_thread" id="cusdis_thread"></div></p>
]]></content:encoded>
      <guid>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-5</guid>
      <pubDate>Mon, 13 Aug 2018 16:04:44 +0000</pubDate>
    </item>
    <item>
      <title>Using MTP with macOS with Node.js: Part 4</title>
      <link>https://gerritniezen.com/using-mtp-with-macos-with-node-js-part-4?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Feature image&#xA;&#xA;In Part 3 I described how I started wrapping libmtp in a Node.js module. Today I discovered napi-macros, which makes writing N-API modules much easier. Recall the getFile function we had from last time:&#xA;    &#xA;napivalue getFile(napienv env, napicallbackinfo info) {&#xA;    napistatus status;&#xA;&#xA;    sizet argc = 2;&#xA;    napivalue argv[2];&#xA;    status = napigetcbinfo(env, info, &amp;argc;, argv, NULL, NULL);&#xA;    if (status != napiok) {&#xA;        napithrowerror(env, NULL, &#34;Failed to parse arguments&#34;);&#xA;    }&#xA;&#xA;    int id = 0;&#xA;    char path[20];&#xA;    napigetvalueint32(env, argv[0], &amp;id;);&#xA;    napigetvaluestringutf8(env, argv[1], path, 20, NULL);&#xA;&#xA;    int ret = LIBMTPGetFileToFile(device, id, path, NULL, NULL);&#xA;&#xA;    napivalue retVal;&#xA;    status = napicreateint32(env, ret, &amp;retVal;);&#xA;    if (status != napiok) {&#xA;        napithrowerror(env, NULL, &#34;Unable to create return value&#34;);&#xA;    }&#xA;&#xA;    return retVal;&#xA;}&#xA;&#xA;I remember when I was writing that it felt very verbose. Now, using napi-macros this collapses into:&#xA;    &#xA;NAPIMETHOD(getFile) {&#xA;  NAPIARGV(2)&#xA;  NAPIARGVINT32(id, 0)&#xA;  NAPIARGVUTF8MALLOC(path, 1)&#xA;&#xA;  int ret = LIBMTPGetFileToFile(device, id, path, NULL, NULL);&#xA;&#xA;  NAPIRETURNINT32(ret)&#xA;}&#xA;&#xA;Wow, that&#39;s quite the difference - succinct and easier to read. I like it!&#xA;&#xA;nodemtp&#xA;&#xA;iComment on this post/i&#xD;&#xA;div id=&#34;cusdisthread&#34;/div]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://images.unsplash.com/photo-1480694313141-fce5e697ee25?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=16cee079798c8b1aa5098bcb994f7af3" alt="Feature image"/></p>

<p>In <a href="https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-3/">Part 3</a> I described how I started wrapping libmtp in a Node.js module. Today I discovered <a href="https://github.com/mafintosh/napi-macros">napi-macros</a>, which makes writing N-API modules much easier. Recall the <code>getFile</code> function we had from last time:</p>

<pre><code class="language-c">napi_value getFile(napi_env env, napi_callback_info info) {
    napi_status status;

    size_t argc = 2;
    napi_value argv[2];
    status = napi_get_cb_info(env, info, &amp;argc;, argv, NULL, NULL);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, &#34;Failed to parse arguments&#34;);
    }

    int id = 0;
    char path[20];
    napi_get_value_int32(env, argv[0], &amp;id;);
    napi_get_value_string_utf8(env, argv[1], path, 20, NULL);

    int ret = LIBMTP_Get_File_To_File(device, id, path, NULL, NULL);

    napi_value retVal;
    status = napi_create_int32(env, ret, &amp;retVal;);
    if (status != napi_ok) {
        napi_throw_error(env, NULL, &#34;Unable to create return value&#34;);
    }

    return retVal;
}
</code></pre>

<p>I remember when I was writing that it felt very verbose. Now, using <code>napi-macros</code> this collapses into:</p>

<pre><code class="language-c">NAPI_METHOD(getFile) {
  NAPI_ARGV(2)
  NAPI_ARGV_INT32(id, 0)
  NAPI_ARGV_UTF8_MALLOC(path, 1)

  int ret = LIBMTP_Get_File_To_File(device, id, path, NULL, NULL);

  NAPI_RETURN_INT32(ret)
}
</code></pre>

<p>Wow, that&#39;s quite the difference – succinct and easier to read. I like it!</p>

<p><a href="https://gerritniezen.com/tag:nodemtp" class="hashtag"><span>#</span><span class="p-category">nodemtp</span></a></p>

<p><i>Comment on this post</i>
<div id="cusdis_thread" id="cusdis_thread"></div></p>
]]></content:encoded>
      <guid>https://gerritniezen.com/using-mtp-with-macos-with-node-js-part-4</guid>
      <pubDate>Thu, 09 Aug 2018 13:52:29 +0000</pubDate>
    </item>
    <item>
      <title>Using MTP on macOS with Node.js: Part 3</title>
      <link>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-3?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Feature image&#xA;&#xA;Today I started on wrapping the libmtp C library in a Node.js module. So far, I&#39;ve managed to load the list of files on the device and successfully retrieve a file.&#xA;&#xA;Let&#39;s start with the bindings.gyp file:&#xA;    &#xA;{&#xA;  &#34;targets&#34;: [{&#xA;      &#34;targetname&#34;: &#34;module&#34;,&#xA;      &#34;sources&#34;: [ &#34;./src/module.c&#34; ],&#xA;      &#34;libraries&#34;: [&#xA;          &#34;&lt;!@(pkg-config --libs libmtp)&#34;&#xA;      ],&#xA;      &#34;cflags&#34;: [&#xA;          &#34;&lt;!@(pkg-config --cflags libmtp)&#34;&#xA;      ]&#xA;  }],&#xA;}&#xA;    &#xA;&#xA;Here I&#39;m specifying that the file containing the C code is in module.c, and that we&#39;re using the libmtp shared library. On macOS, use brew install libmtp. On Linux, use sudo apt-get install libmtp-dev. Oh, you&#39;ll also need pkg-config if it&#39;s not installed on your system yet[1].&#xA;&#xA;Here is the NAPI function to run the code in the C library and return the result to JS:&#xA;    &#xA;napivalue getFile(napienv env, napicallbackinfo info) {&#xA;  napistatus status;&#xA;&#xA;  sizet argc = 2;&#xA;  napivalue argv[2];&#xA;  status = napigetcbinfo(env, info, &amp;argc;, argv, NULL, NULL);&#xA;  if (status != napiok) {&#xA;      napithrowerror(env, NULL, &#34;Failed to parse arguments&#34;);&#xA;  }&#xA;&#xA;  int id = 0;&#xA;  char path[20];&#xA;  napigetvalueint32(env, argv[0], &amp;id;);&#xA;  napigetvaluestringutf8(env, argv[1], path, 20, NULL);&#xA;&#xA;  int ret = LIBMTPGetFileToFile(device, id, path, NULL, NULL);&#xA;&#xA;  napivalue retVal;&#xA;  status = napicreateint32(env, ret, &amp;retVal;);&#xA;  if (status != napiok) {&#xA;      napithrowerror(env, NULL, &#34;Unable to create return value&#34;);&#xA;  }&#xA;&#xA;  return retVal;&#xA;}&#xA;&#xA;For details on how we get the arguments converted from JS to C, and the return value back to JS, see this tutorial. The line to focus on here is the one with LIBMTPGetFileToFile, where we pass the file ID to get from the device, and a path to save that file to.&#xA;&#xA;As we need to connect to the device before we read the file, I added the following code to the NAPI Init function:&#xA;    &#xA;napivalue Init(napienv env, napivalue exports) {&#xA;  napistatus status;&#xA;  napivalue fn;&#xA;&#xA;  LIBMTPInit();&#xA;&#xA;  fprintf(stdout, &#34;libmtp version: &#34; LIBMTPVERSIONSTRING &#34;\n\n&#34;);&#xA;&#xA;  device = LIBMTPGetFirstDevice();&#xA;  if (device == NULL) {&#xA;    printf(&#34;No devices.\n&#34;);&#xA;    return 0;&#xA;  }&#xA;&#xA;  status = napicreatefunction(env, NULL, 0, getFile, NULL, &amp;fn;);&#xA;  if (status != napiok) {&#xA;      napithrowerror(env, NULL, &#34;Unable to wrap native function&#34;);&#xA;  }&#xA;&#xA;  status = napisetnamedproperty(env, exports, &#34;getfiletofile&#34;, fn);&#xA;  if (status != napiok) {&#xA;      napithrowerror(env, NULL, &#34;Unable to populate exports&#34;);&#xA;  }&#xA;&#xA;  return exports;&#xA;}&#xA;&#xA;NAPIMODULE(NODEGYPMODULENAME, Init)&#xA;&#xA;The line with napisetnamedproperty specifies what the function name is called in JS, while napicreatefunction creates a JS function from the C function called getFile.&#xA;&#xA;Now it&#39;s as easy as just calling the function from JS:&#xA;    &#xA;const binding = require(&#39;node-gyp-build&#39;)(dirname);&#xA;    &#xA;console.log(Status:, binding.getfiletofile(1693, &#39;test.jpg&#39;));&#xA;&#xA;We pass the file ID (1693 in this example) and the path to save file into (test.jpg in the same folder). And that&#39;s it, we can read files from an Android phone over MTP on macOS! I&#39;ll be posting all the code on GitHub soon once I&#39;ve cleaned it up a bit.&#xA;&#xA;---&#xA;&#xA;  brew install pkg-config on macOS. ↩︎&#xA;&#xA;nodemtp&#xA;&#xA;iComment on this post/i&#xD;&#xA;div id=&#34;cusdis_thread&#34;/div]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://images.unsplash.com/photo-1480694313141-fce5e697ee25?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=16cee079798c8b1aa5098bcb994f7af3" alt="Feature image"/></p>

<p>Today I started on wrapping the <a href="http://libmtp.sourceforge.net/">libmtp</a> C library in a Node.js module. So far, I&#39;ve managed to load the list of files on the device and successfully retrieve a file.</p>

<p>Let&#39;s start with the <code>bindings.gyp</code> file:</p>

<pre><code class="language-json">{
  &#34;targets&#34;: [{
      &#34;target_name&#34;: &#34;module&#34;,
      &#34;sources&#34;: [ &#34;./src/module.c&#34; ],
      &#34;libraries&#34;: [
          &#34;&lt;!@(pkg-config --libs libmtp)&#34;
      ],
      &#34;cflags&#34;: [
          &#34;&lt;!@(pkg-config --cflags libmtp)&#34;
      ]
  }],
}
</code></pre>

<p>Here I&#39;m specifying that the file containing the C code is in <code>module.c</code>, and that we&#39;re using the <code>libmtp</code> shared library. On macOS, use <code>brew install libmtp</code>. On Linux, use <code>sudo apt-get install libmtp-dev</code>. Oh, you&#39;ll also need <code>pkg-config</code> if it&#39;s not installed on your system yet[1].</p>

<p>Here is the NAPI function to run the code in the C library and return the result to JS:</p>

<pre><code class="language-c">napi_value getFile(napi_env env, napi_callback_info info) {
  napi_status status;

  size_t argc = 2;
  napi_value argv[2];
  status = napi_get_cb_info(env, info, &amp;argc;, argv, NULL, NULL);
  if (status != napi_ok) {
      napi_throw_error(env, NULL, &#34;Failed to parse arguments&#34;);
  }

  int id = 0;
  char path[20];
  napi_get_value_int32(env, argv[0], &amp;id;);
  napi_get_value_string_utf8(env, argv[1], path, 20, NULL);

  int ret = LIBMTP_Get_File_To_File(device, id, path, NULL, NULL);

  napi_value retVal;
  status = napi_create_int32(env, ret, &amp;retVal;);
  if (status != napi_ok) {
      napi_throw_error(env, NULL, &#34;Unable to create return value&#34;);
  }

  return retVal;
}
</code></pre>

<p>For details on how we get the arguments converted from JS to C, and the return value back to JS, see <a href="https://hackernoon.com/n-api-and-getting-started-with-writing-c-addons-for-node-js-cf061b3eae75">this tutorial</a>. The line to focus on here is the one with <code>LIBMTP_Get_File_To_File</code>, where we pass the file ID to get from the device, and a path to save that file to.</p>

<p>As we need to connect to the device before we read the file, I added the following code to the NAPI <code>Init</code> function:</p>

<pre><code class="language-c">napi_value Init(napi_env env, napi_value exports) {
  napi_status status;
  napi_value fn;

  LIBMTP_Init();

  fprintf(stdout, &#34;libmtp version: &#34; LIBMTP_VERSION_STRING &#34;\n\n&#34;);

  device = LIBMTP_Get_First_Device();
  if (device == NULL) {
    printf(&#34;No devices.\n&#34;);
    return 0;
  }

  status = napi_create_function(env, NULL, 0, getFile, NULL, &amp;fn;);
  if (status != napi_ok) {
      napi_throw_error(env, NULL, &#34;Unable to wrap native function&#34;);
  }

  status = napi_set_named_property(env, exports, &#34;get_file_to_file&#34;, fn);
  if (status != napi_ok) {
      napi_throw_error(env, NULL, &#34;Unable to populate exports&#34;);
  }

  return exports;
}

NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
</code></pre>

<p>The line with <code>napi_set_named_property</code> specifies what the function name is called in JS, while <code>napi_create_function</code> creates a JS function from the C function called <code>getFile</code>.</p>

<p>Now it&#39;s as easy as just calling the function from JS:</p>

<pre><code class="language-js">const binding = require(&#39;node-gyp-build&#39;)(__dirname);
    
console.log(`Status:`, binding.get_file_to_file(1693, &#39;test.jpg&#39;));
</code></pre>

<p>We pass the file ID (1693 in this example) and the path to save file into (<code>test.jpg</code> in the same folder). And that&#39;s it, we can read files from an Android phone over MTP on macOS! I&#39;ll be posting all the code on GitHub soon once I&#39;ve cleaned it up a bit.</p>

<hr/>
<ol><li><code>brew install pkg-config</code> on macOS. ↩︎</li></ol>

<p><a href="https://gerritniezen.com/tag:nodemtp" class="hashtag"><span>#</span><span class="p-category">nodemtp</span></a></p>

<p><i>Comment on this post</i>
<div id="cusdis_thread" id="cusdis_thread"></div></p>
]]></content:encoded>
      <guid>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-3</guid>
      <pubDate>Wed, 01 Aug 2018 13:47:04 +0000</pubDate>
    </item>
    <item>
      <title>Using MTP on macOS with Node.js: Part 2</title>
      <link>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-2?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Feature image&#xA;&#xA;Following up from yesterday, I started using libmtp to see if I can connect to an Android phone and read a file from it. Once the library is successfully compiled, you can run some of the example programs in the examples/ folder. To list all the files on your device, run ./mtp-files. Then, to retrieve a file, you can run&#xA;    &#xA;./mtp-connect --getfile FILENUMBER DESTINATION&#xA;&#xA;It seems to work just fine, so the next step is to wrap it as a Node.js library. There&#39;s a great article by Mathias Buus on the past and present of handling native (C/C++) modules in Node.js. Basically, N-API is the way to go. It&#39;s already stable in Node v10, and works in Node v8 as well.&#xA;&#xA;I followed this tutorial to build a basic native module with N-API, and it works great. The best part was building it and running it in Node v10, and then running the same code in Node v8 without any issues. Nice!&#xA;&#xA;nodemtp&#xA;&#xA;iComment on this post/i&#xD;&#xA;div id=&#34;cusdisthread&#34;/div]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://images.unsplash.com/photo-1480694313141-fce5e697ee25?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=16cee079798c8b1aa5098bcb994f7af3" alt="Feature image"/></p>

<p>Following up from <a href="https://gerritniezen.com/using-mtp-on-macos/">yesterday</a>, I started using <a href="http://libmtp.sourceforge.net/">libmtp</a> to see if I can connect to an Android phone and read a file from it. Once the library is successfully compiled, you can run some of the example programs in the <code>examples/</code> folder. To list all the files on your device, run <code>./mtp-files</code>. Then, to retrieve a file, you can run</p>

<pre><code>./mtp-connect --getfile &lt;FILE_NUMBER&gt; &lt;DESTINATION&gt;
</code></pre>

<p>It seems to work just fine, so the next step is to wrap it as a Node.js library. There&#39;s a <a href="https://www.nearform.com/blog/the-future-of-native-modules-in-node-js/">great article by Mathias Buus</a> on the past and present of handling native (C/C++) modules in Node.js. Basically, <a href="https://nodejs.org/api/n-api.html">N-API</a> is the way to go. It&#39;s already stable in Node v10, and works in Node v8 as well.</p>

<p>I followed <a href="https://hackernoon.com/n-api-and-getting-started-with-writing-c-addons-for-node-js-cf061b3eae75">this tutorial</a> to build a basic native module with N-API, and it works great. The best part was building it and running it in Node v10, and then running the same code in Node v8 <em>without any issues</em>. Nice!</p>

<p><a href="https://gerritniezen.com/tag:nodemtp" class="hashtag"><span>#</span><span class="p-category">nodemtp</span></a></p>

<p><i>Comment on this post</i>
<div id="cusdis_thread" id="cusdis_thread"></div></p>
]]></content:encoded>
      <guid>https://gerritniezen.com/using-mtp-on-macos-with-node-js-part-2</guid>
      <pubDate>Tue, 31 Jul 2018 16:10:32 +0000</pubDate>
    </item>
    <item>
      <title>Using MTP on macOS with Node.js</title>
      <link>https://gerritniezen.com/using-mtp-on-macos-with-node-js?pk_campaign=rss-feed</link>
      <description>&lt;![CDATA[Feature image&#xA;&#xA;Media Transfer Protocol (MTP) has replaced USB Mass Storage as the dominant protocol for transferring digital media between an Android phone and a computer. USB Mass Storage allows devices to be mounted as drives on the host computer, and while MTP also allows drives to be mounted, it happens at a level where it&#39;s easier to restrict which files are made available to the host system. If that sounds to you like something Microsoft would design, you&#39;d be right.&#xA;&#xA;MTP works great on Windows machines of course, and surprisingly well on Linux. However, while there&#39;s apparently some basic MTP support on macOS, it doesn&#39;t even allow you to mount a device without external software, like Android File Transfer.&#xA;&#xA;I spent some time today looking at options for connecting to an Android phone on macOS with MTP using Node.js. Here are some possible options:&#xA;&#xA;  Use FUSE (Filesystem in Userspace) with Node bindings. This will requires installation of FUSE for macOS  first, which I think also involves installing a kernel extension. So it&#39;s basically a no-go for macOS High Sierra and above.&#xA;  Write a wrapper for libmtp, using this unmaintained repo as a base.&#xA;  Port parts of this application over to Node.js, as its only dependency seems to be libusb. This means essentially writing your own MTP implementation on top of node-usb.&#xA;&#xA;Since MTP has been standardised as part of the USB Device Class specifications, writing an MTP implementation on node-usb does make sense, but will probably be a lot of work. I think I will opt for (2) first as it&#39;s easier, with (3) as a fallback.&#xA;&#xA;nodemtp&#xA;&#xA;iComment on this post/i&#xD;&#xA;div id=&#34;cusdisthread&#34;/div]]&gt;</description>
      <content:encoded><![CDATA[<p><img src="https://images.unsplash.com/photo-1512149673953-1e251807ec7c?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=f6846594c95983b1ddc334c023b9df64" alt="Feature image"/></p>

<p>Media Transfer Protocol (MTP) has replaced USB Mass Storage as the dominant protocol for transferring digital media between an Android phone and a computer. USB Mass Storage allows devices to be mounted as drives on the host computer, and while MTP also allows drives to be mounted, it happens at a level where it&#39;s easier to restrict which files are made available to the host system. If that sounds to you like something Microsoft would design, you&#39;d be right.</p>

<p>MTP works great on Windows machines of course, and surprisingly well on Linux. However, while there&#39;s apparently some basic MTP support on macOS, it doesn&#39;t even allow you to mount a device without external software, like <a href="https://www.android.com/filetransfer/">Android File Transfer</a>.</p>

<p>I spent some time today looking at options for connecting to an Android phone on macOS with MTP using Node.js. Here are some possible options:</p>
<ol><li>Use FUSE (Filesystem in Userspace) with <a href="https://github.com/mafintosh/fuse-bindings">Node bindings</a>. This will requires installation of <a href="https://osxfuse.github.io/">FUSE for macOS </a> first, which I think also involves installing a kernel extension. So it&#39;s basically a no-go for <a href="https://blog.eriknicolasgomez.com/2017/07/25/Kextpocalypse-High-Sierra-and-kexts-in-the-Enterprise/">macOS High Sierra and above</a>.</li>
<li>Write a wrapper for <a href="http://libmtp.sourceforge.net/">libmtp</a>, using this <a href="https://github.com/panuhorsmalahti/mtp">unmaintained repo</a> as a base.</li>
<li>Port parts of <a href="https://github.com/whoozle/android-file-transfer-linux">this application</a> over to Node.js, as its only dependency seems to be libusb. This means essentially writing your own MTP implementation on top of <a href="https://github.com/tessel/node-usb">node-usb</a>.</li></ol>

<p>Since MTP has been standardised as part of the <a href="http://www.usb.org/developers/docs/devclass_docs/">USB Device Class specifications</a>, writing an MTP implementation on node-usb does make sense, but will probably be a lot of work. I think I will opt for (2) first as it&#39;s easier, with (3) as a fallback.</p>

<p><a href="https://gerritniezen.com/tag:nodemtp" class="hashtag"><span>#</span><span class="p-category">nodemtp</span></a></p>

<p><i>Comment on this post</i>
<div id="cusdis_thread" id="cusdis_thread"></div></p>
]]></content:encoded>
      <guid>https://gerritniezen.com/using-mtp-on-macos-with-node-js</guid>
      <pubDate>Mon, 30 Jul 2018 19:15:37 +0000</pubDate>
    </item>
  </channel>
</rss>